J'étais en voyage d'affaires il y a quelques jours et j'ai vu le panneau de surveillance aérien dans l'avion. En plus de diffuser des séries télévisées et des publicités, il passait également de temps en temps à un système de surveillance pour la navigation aérienne. Le système semblait un peu rudimentaire, alors sur un coup de tête, j'ai créé une version améliorée du système de surveillance en utilisant HT pour le Web. La démo est plutôt bonne, j'aimerais donc la partager avec vous afin que nous puissions apprendre les uns des autres.
démo
Processus de mise en œuvreEffet de marche à travers les nuages
Afin d'obtenir l'effet d'un avion volant à travers les nuages, le premier problème que j'ai rencontré était la superposition du vol de l'avion, communément appelée effet de perspective. Ici, j'ai utilisé le canal nuageux et le fond nuageux pour circuler à différentes vitesses. pour créer un effet de perspective volante.
J'ai présenté les nuages sous forme de textures, mais seules les textures bloqueraient le ciel et l'avion, ce qui affecterait grandement l'apparence et la sensation de l'avion en vol, j'ai donc activé la transparence et l'opacité des éléments graphiques correspondants, et définissez différents niveaux de transparence pour l'arrière-plan du nuage et le canal du nuage. Non seulement cela ajoute une impression de superposition, mais cela donne également aux gens l'illusion de nuages dérivant devant leurs yeux.
Le canal nuage utilise le type ht.Polyline. La mise à l'échelle du canal agrandit la proportion de l'axe Y, donnant au canal nuage un espace vertical plus grand. Le réglage de la copie inversée permet d'afficher la texture à l'intérieur du canal nuage, comme. si l'avion est dans les airs et voyage à travers la mer de nuages ; le fond de nuage adopte le type ht.Node et une seule surface est définie pour être affichée comme fond de nuage.
L'effet global d'écoulement des nuages est obtenu à l'aide d'un décalage de décalage, et le décalage de texture de la primitive correspondante ou de la surface primitive correspondante est modifié pour obtenir l'effet d'un avion voyageant à travers les nuages. Le code est le suivant :
var je = 1, p = 0;setInterval(() => { je -= 0,1; p += 0,005; nuages.s('shape3d.uv.offset', [i, 0]); cloudBackground.s(' all.uv.offset', [p, 0]);}, 100);
Effet de bosse liftante
Bien que cela donne l'effet d'un avion volant à travers les nuages, si l'avion vole uniquement en ligne droite, cela réduira également la sensation réelle de voler. Je crois que les amis qui ont volé dans un avion ont dû rencontrer des turbulences causées par le flux d'air, et souvent. ressentez les turbulences causées par le vol de l'avion. La montée et la descente en cours de route sont en fait dues au fait que la route de l'avion n'est pas toujours fixée à une certaine altitude. Parfois, il monte et parfois descend, j'ai donc utilisé le plug d'extension d'animation ht-animation.js
-in pour obtenir l'effet bosselé de l'avion. Le code est le suivant :
dm.enableAnimation(20);plane.setAnimation({ back1 : { de : 0 à : 160, assouplissement : 'Cubic.easeInOut', durée : 8 000, suivant : up1, onUpdate : function (value) { value = parseInt( valeur); var p3 = this.p3(); this.p3(valeur, p3[1], p3[2]); }, //...Omettre le début similaire : [back1]});Restrictions d'angle de vision du secteur de la sphère
Une fois l'effet de vol perfectionné, j'ai rencontré un problème plus difficile, car même si l'avion volait à travers la mer de nuages, il ne volait que dans le canal, et l'arrière-plan n'était en fait qu'une texture plate, donc quand le la perspective a atteint un certain niveau. Lorsque ce niveau est atteint, il y aura un fort sentiment de dissonance et d'irréalité, et une limite d'angle de vision est nécessaire pour effectuer l'ajustement de l'angle de vision juste dans une certaine plage.
Les restrictions d'angle de vision limitent généralement l'œil et le centre de g3d. Les amis qui n'y connaissent pas grand-chose peuvent lire le manuel 3D sur le site officiel de hightopo, qui contient des instructions détaillées. Je n'entrerai pas dans les détails ici à cause de la visualisation. plage d'angle, j'ai décidé de fixer la position du centre, le code est le suivant :
g3d.addPropertyChangeListener(e => { // Point central fixe if (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = centre[2];
Limitez ensuite l'œil à une certaine plage et vous avez terminé. Cependant, ce n'est pas si simple ici. Au début, j'ai limité l'œil à un espace cubique, mais l'effet d'interaction n'était pas idéal étant donné que dans l'interaction par défaut de g3d. , la souris Lorsque vous faites glisser et effectuez un panoramique pour changer la perspective, l'œil se déplace en fait sur une surface sphérique avec le centre comme centre, j'ai donc décidé de creuser un morceau d'espace restreint pour l'œil à partir de la balle, qui est un secteur sphérique. Pour ceux qui ne comprennent pas bien, vous pouvez vous référer à cette image :
La limite d'angle de vision en forme d'éventail sphérique nécessite un total de trois paramètres, à savoir l'axe de référence central, l'angle entre l'axe central et le bord extérieur et le rayon limité de la balle. L'axe de référence central peut être déterminé en fonction de. ligne d'extension reliant l'œil initial et le centre, et le rayon limité de la balle est localisé. Il est divisé en limite maximale et limite minimale. Le code est le suivant :
function limitEye(g3d, eye, center, options) { var limitMaxL = options.limitMaxL, limitMinL = options.limitMinL, limitA = options.limitA; == 'centre') { e.newValue[0] = centre[0]; e.newValue[1] = centre[1]; e.newValue[2] = center[2]; } // Limiter l'angle de vision if (e.property === 'eye') { var newEyeV = new ht.Math.Vector3(e.newValue), centerV = new ht. Math.Vector3(centre), refEyeV = nouveau ht.Math.Vector3(oeil), refVector = refEyeV.clone().sub(centerV), newVector = newEyeV.clone().sub(centerV); if (centerV.distanceTo(newEyeV) > limitMaxL) { newVector.setLength(limitMaxL); e.newValue[0] = e.newValue[1] = newVector.y; e.newValue[2] = newVector.z; } if (centerV.distanceTo(newEyeV) < limitMinL) { newVector.setLength(limitMinL); e.newValue[0] = newVector.x; e.newVector.y; e.newValue[2] = newVector.z; refVector) > limitA) { var oldLength = newVector.length(), oldAngle = newVector.angleTo(refVector), refLength = oldLength * Math.cos(oldAngle), vertVector, realVector, realEye; refVector.setLength(refLength); vertVector = newEyeV.clone().sub(refEyeV); vertLength = refLength * Math.tan(limitA); vertVector.setLength(vertLength); realVector = vertVector.clone().add(refEyeV).sub(centerV); .add(centerV); // Empêche l'angle de mouvement d'être supérieur à 180 degrés et inverse la perspective if (oldAngle > Math.PI / 2) { realEye.negate(); e.newValue[0] = realEye.x; e.newValue[1] = realEye.y; )}système de surveillance des avions
Bien sûr, en tant que système de surveillance, il est naturel d'avoir une surveillance. Ajoutez une petite carte dans le coin inférieur droit et proposez trois modes : se concentrer sur l'avion, se concentrer sur la trajectoire de vol et se concentrer sur la carte, et contrôler l'effet de flux. de la trajectoire de vol en fonction de la direction de vol de l'avion. Parmi eux, la mise au point sur l'avion suivra le mouvement de l'avion et effectuera fitData pour que l'avion soit toujours au centre de la mini-carte.
var fitFlowP = function (e) { if (e.property === 'position' && e.data === plan) { mapGV.fitData(plane, false }};buttonP.s({ 'interactif' : true, 'onClick' : fonction (événement, données, vue, point, largeur, hauteur) { map.a('fitDataTag', 'plane2D'); mapDM.md(fitFlowP); }});buttonL.s({ 'interactif' : true, 'onClick' : fonction (événement, données, vue, point, largeur, hauteur) { mapDM.umd(fitFlowP); map. a('fitDataTag', 'flyLine'); mapGV.fitData(flyLine, false }});// ...omis;
Ajout d'invites pour déplacer la souris vers la position correspondante de l'avion pour le nommer, double-cliquer pour afficher le panneau d'informations de la position correspondante de l'avion et focaliser la perspective sur le panneau, cliquer n'importe où sur l'avion pour revenir à la mode de vol de l'avion et autres effets.
L'ajout d'un panneau de surveillance à gauche remplace le double-clic mentionné ci-dessus sur la position correspondante, qui se concentre directement sur le panneau d'information à la position correspondante. Le bouton ici permet l'interaction et ajoute la logique d'interaction correspondante. Le code est le suivant :
bouton_JC.s({ 'interactif' : vrai, 'onClick' : fonction (événement, données, vue, point, largeur, hauteur) { event.preventDefault(); let g3d = G.g3d, g3dDM = G.g3d.dm (); g3d.fireInteractorEvent({ genre : 'doubleClickData', données : g3dDM.getDataByTag(data.getTag()) }) }});//...omisEffet de rendu du ciel
Puisqu'il s'agit d'un système de surveillance, il doit être surveillé 24 heures sur 24 sans distinction. Cela pose un problème. Il m'est impossible de survoler le ciel bleu en pleine nuit. Cela manque d'authenticité, il doit donc y avoir un problème. Le processus du ciel de la lumière à l'obscurité, puis de l'obscurité à la lumière, j'ai provisoirement réglé ce processus sur les deux périodes de 06h00 à 06h30 et de 19h00 à 19h30.
Le ciel utilise une forme sphérique shape3d: 'sphere' pour envelopper toute la scène, puis utilisez reverse.flip pour copier et mélanger la teinture. Après cela, le ciel peut être rendu dans la couleur que je souhaite. lumière et ombre du ciel en fonction du temps, il me suffit de changer la valeur de la teinture.
Cependant, en raison des différentes conditions d'éclairage entre le jour et la nuit, l'intensité de la lumière réfléchie par les nuages est également différente, ce qui entraîne une différence entre les nuages de jour et de nuit. Par conséquent, il est également nécessaire d'ajuster la transparence de l'opacité du nuage. textures de fond de canal et de nuage, plus transparentes la nuit. Le code est le suivant :
if ((heure > 6 && heure < 19) || (heure == 6 && minutes >= 30)) { timePane && timePane.a({ 'morning.visible' : false, 'day.visible' : true, ' crépuscule.visible' : faux, 'nuit.visible' : faux, 'jour.opacité' : 1 }) skyBox.s({ shape3d.blend : 'rgb(127, 200, 240)', }) cloudBackground.s({ back.opacity : 0,7, }) clouds.s({ shape3d.opacity : 0,7, })} else if ((heure < 6 || heure > 19) || (heure == 19 && minutes >= 30)) {//...omis} sinon si (heure == 6 && minutes < 15 ) {//...omis} sinon si (heure == 6 && minutes >= 15 && minutes < 30) {//...omis} sinon si (heure == 19 && minutes < 15) { //...Omis} else if (heure == 19 && minutes >= 15 && minutes < 30) {//...Omis}
Ici, j'ai également ajouté la prise en charge de l'icône d'état de l'heure dans le coin supérieur droit du panneau d'heure, et ajouté un effet de fondu d'entrée et de sortie lorsque l'icône est commutée. En même temps, j'ai ajouté un clic pour basculer. à la position suivante de l'icône d'état de l'heure pour l'icône d'état du panneau horaire.
Afin de démontrer l'effet, j'ai ajouté un bouton de doublement du temps. L'image suivante montre les changements à 500 fois le débit temporel :
RésumerGrâce à cette démo, j'ai découvert qu'il existe de nombreux détails dans la vie qui n'ont pas été remarqués par les gens, et qu'il existe une possibilité de visualisation des données. À l'ère du Big Data, d'autres possibilités méritent d'être explorées. autour de vous, visualiser les détails peut non seulement mieux exploiter le potentiel de HT pour le Web, mais également renforcer la qualité globale d'un programmeur.