Ich war vor ein paar Tagen auf einer Geschäftsreise und habe das Overhead-Überwachungspanel im Flugzeug gesehen. Neben der Abspielung von Fernsehserien und Werbespots wurde von Zeit zu Zeit auch auf ein Überwachungssystem für die Flugzeugnavigation umgestellt Das System fühlte sich etwas grob an, also habe ich aus einer Laune heraus eine aktualisierte Version des Überwachungssystems mit HT für Web erstellt. Die Demo ist ziemlich gut, deshalb möchte ich sie mit Ihnen teilen, damit wir voneinander lernen können.
Demo
ImplementierungsprozessDer Effekt „Durch die Wolken gehen“
Um den Effekt eines durch die Wolken fliegenden Flugzeugs zu erzielen, war das erste Problem, auf das ich stieß, die Schichtung des Flugzeugflugs, die allgemein als perspektivischer Effekt bekannt ist. Hier habe ich den Wolkenkanal und den Wolkenhintergrund verwendet, um mit unterschiedlichen Geschwindigkeiten zu fließen um einen fliegenden Perspektiveffekt zu erzeugen.
Ich habe die Wolken in Form von Texturen dargestellt, aber nur die Texturen würden den Himmel und das Flugzeug blockieren, was sich stark auf das Erscheinungsbild des fliegenden Flugzeugs auswirken würde, also habe ich die Transparenz und Deckkraft der entsprechenden Grafikelemente aktiviert und Legen Sie unterschiedliche Transparenzstufen für den Wolkenhintergrund und den Wolkenkanal fest. Dadurch entsteht nicht nur ein Gefühl von Schichtung, sondern es entsteht auch die Illusion, dass Wolken vor ihren Augen vorbeiziehen.
Der Wolkenkanal verwendet den Typ ht.Polyline. Durch die Kanalskalierung wird der Anteil der Y-Achse vergrößert, wodurch der Wolkenkanal einen größeren vertikalen Raum erhält, sodass die Textur innerhalb des Wolkenkanals angezeigt werden kann Wenn das Flugzeug durch das Wolkenmeer fliegt, übernimmt der Wolkenhintergrund den Typ ht.Node und es wird nur eine Oberfläche als Wolkenhintergrund angezeigt.
Der gesamte Wolkenströmungseffekt wird durch Versatzversatz erreicht, und der Texturversatz des entsprechenden Grundelements oder der entsprechenden Grundelementoberfläche wird geändert, um den Effekt eines durch Wolken fliegenden Flugzeugs zu erzielen. Der Code lautet wie folgt:
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);
Lifting-Bump-Effekt
Obwohl es den Effekt eines durch die Wolken fliegenden Flugzeugs erzielt, verringert es auch das tatsächliche Fluggefühl, wenn das Flugzeug nur geradeaus fliegt. Ich glaube, dass Freunde, die in einem Flugzeug geflogen sind, oft auf Turbulenzen gestoßen sein müssen, die durch Luftströmungen verursacht werden Spüren Sie die durch den Flug verursachten Turbulenzen, da die Route des Flugzeugs nicht immer auf einer bestimmten Höhe liegt. Daher habe ich den HT-Animationserweiterungsstecker ht-animation.js
verwendet -in, um den holprigen Effekt des Flugzeugs zu erzielen. Der Code lautet wie folgt:
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]); }, //...Ähnliches weglassen start: [back1]});Einschränkungen des Betrachtungswinkels des Kugelsektors
Nachdem der Flugeffekt perfektioniert war, stieß ich auf ein schwierigeres Problem, denn obwohl das Flugzeug tatsächlich durch das Wolkenmeer flog, flog es nur im Kanal und der Hintergrund war eigentlich nur eine flache Textur Die Perspektive hat ein bestimmtes Niveau erreicht. Wenn dieses Niveau erreicht ist, entsteht ein starkes Gefühl von Dissonanz und Unwirklichkeit, und es ist eine Betrachtungswinkelbegrenzung erforderlich, um die Anpassung des Betrachtungswinkels nur innerhalb eines bestimmten Bereichs vorzunehmen.
Betrachtungswinkelbeschränkungen schränken im Allgemeinen das Auge und die Mitte von g3d ein. Freunde, die nicht viel darüber wissen, können das 3D-Handbuch auf der offiziellen Website von Hightopo lesen. Aus Gründen der Betrachtung werde ich hier nicht näher darauf eingehen Winkelbereich, ich habe beschlossen, die Position der Mitte zu fixieren, der Code lautet wie folgt:
g3d.addPropertyChangeListener(e => { // Fester Mittelpunkt if (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = center[2];
Dann beschränken Sie das Auge auf einen bestimmten Bereich und fertig. Allerdings habe ich das Auge zunächst auf einen kubischen Raum beschränkt, aber der Interaktionseffekt war in der Standardinteraktion von g3d nicht ideal , die Maus Beim Ziehen und Schwenken zum Ändern der Perspektive bewegt sich das Auge tatsächlich auf einer sphärischen Oberfläche mit der Mitte als Mittelpunkt, daher habe ich beschlossen, aus der Kugel ein Stück begrenzten Raum für das Auge herauszuschneiden, bei dem es sich um einen sphärischen Sektor handelt. Für diejenigen, die es nicht gut verstehen: Sie können sich auf dieses Bild beziehen:
Die sphärische fächerförmige Betrachtungswinkelgrenze erfordert insgesamt drei Parameter, nämlich die zentrale Referenzachse, den Winkel zwischen der zentralen Achse und der Außenkante und den begrenzten Radius der Kugel. Die zentrale Referenzachse kann anhand der bestimmt werden Die Verlängerungslinie, die das anfängliche Auge und die Mitte verbindet, ist der begrenzte Radius der Kugel. Er ist in maximale Grenze und minimale Grenze unterteilt.
function limitEye(g3d, eye, center, options) { var limitMaxL = options.limitMaxL, limitMinL = options.limitMinL, limitA = options.limitA; g3d.addPropertyChangeListener(e => { // Fester Mittelpunkt if (e.property = == 'center') { e.newValue[0] = center[0]; e.newValue[2] = center[2]; } // Betrachtungswinkel begrenzen 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[1] = newVector.y; e.newValue[2] = newVector.z } if (centerV.distanceTo(newEyeV) < limitMinL) { newVector.setLength(limitMinL); e.newValue[1] = newVector.y; } if (newVector.angleTo( refVector) > limitA) { var oldLength = newVector.length(), oldAngle = newVector.angleTo(refVector), refLength = oldLength * Math.cos(oldAngle), vertVector, realVector, realEye; newEyeV = newVector.clone().add(centerV); vertVector = newEyeV.clone().sub(refEyeV); vertLength = refLength * Math.tan(limitA); realVector = vertVector.clone().add(refEyeV).sub(centerV(oldLength); realEye = realVector.clone(); .add(centerV); // Verhindern Sie, dass der Bewegungswinkel größer als 180 Grad ist, und kehren Sie die Perspektive um, wenn (oldAngle > Math.PI / 2) { realEye.negate(); e.newValue[0] = realEye.x; e.newValue[2] = realEye.z; )}Flugzeugüberwachungssystem
Als Überwachungssystem ist es natürlich selbstverständlich, in der unteren rechten Ecke eine kleine Karte hinzuzufügen und drei Modi bereitzustellen: Fokus auf das Flugzeug, Fokus auf die Flugbahn und Fokus auf die Karte sowie Steuerung des Strömungseffekts Der Fokus auf die Flugbahn richtet sich nach der Flugrichtung des Flugzeugs und führt fitData aus, sodass sich das Flugzeug immer in der Mitte der Minikarte befindet.
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'); 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 }});// ...ausgelassen
Eingabeaufforderungen hinzugefügt, um die Maus an die entsprechende Position des Flugzeugs zu bewegen, um es zu benennen, einen Doppelklick auszuführen, um das Informationsfeld der entsprechenden Position des Flugzeugs anzuzeigen und die Perspektive auf das Feld zu fokussieren, und auf eine beliebige Stelle des Flugzeugs zu klicken, um zurück zu wechseln Flugmodus des Flugzeugs und andere Effekte.
Das Hinzufügen eines Überwachungsfelds auf der linken Seite ersetzt den oben erwähnten Doppelklick auf die entsprechende Position, der sich direkt auf das Informationsfeld an der entsprechenden Position konzentriert. Die Schaltfläche hier ermöglicht die Interaktion und fügt die entsprechende Interaktionslogik hinzu.
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()) }) }});//...ausgelassenSky-Rendering-Effekt
Da es sich um ein Überwachungssystem handelt, muss es 24 Stunden am Tag unterschiedslos überwacht werden. Es ist für mich unmöglich, mitten in der Nacht über den blauen Himmel zu fliegen, also muss es eine geben Der Prozess des Himmels von hell nach dunkel und dann von dunkel nach hell. Ich habe diesen Prozess vorläufig auf die beiden Zeiträume 06:00–06:30 Uhr und 19:00–19:30 Uhr festgelegt.
Der Himmel verwendet eine kugelförmige Form von shape3d: „sphere“, um die gesamte Szene zu umhüllen, und verwendet dann „reverse.flip“, um die Farbe zurückzukopieren und zu mischen. Danach kann der Himmel in die gewünschte Farbe gerendert werden Um Licht und Schatten des Himmels entsprechend der Zeit anzupassen, muss ich nur den Farbstoffwert ändern.
Aufgrund der unterschiedlichen Lichtverhältnisse zwischen Tag und Nacht ist jedoch auch die Intensität des von der Wolke reflektierten Lichts unterschiedlich, was zu Unterschieden zwischen den Wolken bei Tag und Nacht führt. Daher ist es auch erforderlich, die Opazitätstransparenz der Wolke anzupassen Kanal- und Wolkenhintergrundtexturen, die nachts transparenter sind. Der Code lautet wie folgt:
if ((Stunde > 6 && Stunde < 19) || (Stunde == 6 && Minuten >= 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 ((Stunde < 6 || Stunde > 19) ||. (Stunde == 19 && Minuten >= 30)) {//...weggelassen} sonst wenn (Stunde == 6 && Minuten < 15 ) {//... weggelassen} else if (Stunde == 6 && Minuten >= 15 && Minuten < 30) {//... weggelassen} sonst if (Stunde == 19 && Minuten < 15) { //...Omitted} else if (Stunde == 19 && Minuten >= 15 && Minuten < 30) {//...Omitted}
Hier habe ich auch Unterstützung für das Zeitstatussymbol in der oberen rechten Ecke des Zeitfensters hinzugefügt und einen Ein- und Ausblendeffekt hinzugefügt, wenn das Symbol gewechselt wird. Gleichzeitig habe ich einen Click-to-Switch hinzugefügt zur nächsten Position des Zeitstatussymbols für das Zeitfenster-Statussymbol.
Um den Effekt zu demonstrieren, habe ich einen Zeitverdopplungsknopf hinzugefügt. Das folgende Bild zeigt die Änderungen bei der 500-fachen Zeitflussrate:
ZusammenfassenDurch diese Demo habe ich herausgefunden, dass es viele Details im Leben gibt, die von den Menschen nicht bemerkt wurden, und dass es die Möglichkeit der Datenvisualisierung gibt. Im Zeitalter von Big Data lohnt es sich, mehr Möglichkeiten zu erkunden. Verpassen Sie nicht alle wertvollen Daten Die Visualisierung von Details kann nicht nur das Potenzial von HT für das Web besser ausschöpfen, sondern auch die allgemeine Qualität eines Programmierers stärken.