Несколько дней назад я был в командировке и увидел в самолете потолочную панель мониторинга. Помимо воспроизведения сериалов и рекламы, она также время от времени переключалась на систему мониторинга навигации самолета. Однако весь мониторинг. Система показалась мне немного грубой, поэтому по прихоти я сделал обновленную версию системы мониторинга с использованием HT for Web. Демо-версия довольно хороша, поэтому я хотел бы поделиться ею с вами, чтобы мы могли учиться друг у друга.
демо
Процесс реализацииЭффект прогулки сквозь облака
Чтобы добиться эффекта полета самолета сквозь облака, первой проблемой, с которой я столкнулся, было наложение слоев полета самолета, широко известное как эффект перспективы. Здесь я использовал канал облаков и фон облаков для потока с разными скоростями. для создания эффекта летящей перспективы.
Облака я представил в виде текстур, но именно текстуры закрывали небо и самолет, что сильно влияло на внешний вид летящего самолета, поэтому я включил прозрачность и непрозрачность соответствующих графических элементов, и установите разные уровни прозрачности для фона облаков и канала облаков. Это не только добавляет ощущение многослойности, но и дает людям иллюзию проплывающих перед их глазами облаков.
Канал облака использует тип ht.Polyline. Масштабирование канала увеличивает пропорцию оси Y, предоставляя каналу облака большее вертикальное пространство. Установка обратной копии обратного отражения позволяет отображать текстуру внутри канала облака. если самолет находится в воздухе. Путешествуя по морю облаков, фон облаков принимает тип ht.Node, и в качестве фона облаков устанавливается только одна поверхность.
Общий эффект потока облаков достигается с помощью смещения смещения, а смещение текстуры соответствующего примитива или соответствующей примитивной поверхности изменяется для достижения эффекта полета самолета через облака. Код выглядит следующим образом:
var i = 1, p = 0; setInterval(() => { i -= 0,1; p += 0,005; cloud.s('shape3d.uv.offset', [i, 0]); cloudBackground.s(' all.uv.offset', [p, 0]);}, 100);
Лифтинг-эффект
Несмотря на то, что достигается эффект полета самолета сквозь облака, если самолет летит только прямо, это также уменьшит реальное ощущение полета. Я считаю, что друзья, которые летали на самолете, наверняка сталкивались с турбулентностью, вызванной воздушным потоком, и часто. почувствуйте турбулентность, вызванную полетом самолета. Подъем и снижение по пути на самом деле связаны с тем, что маршрут самолета не всегда фиксирован на определенной высоте. Иногда он поднимается, а иногда падает, поэтому я использовал плагин расширения анимации HT ht-animation.js
-in для достижения ухабистого эффекта самолета. Код выглядит следующим образом:
dm.enableAnimation(20);plane.setAnimation({ back1: { from: 0, to: 160, easing: 'Cubic.easeInOut', продолжительность: 8000, следующая: up1, onUpdate: function (value) { value = parseInt( значение); вар p3 = this.p3(); this.p3(значение, p3[1], p3[2]); }, //...Пропустить аналогичный start: [back1]});Ограничения угла обзора сектора сферы
После того, как эффект полета был доведен до совершенства, я столкнулся с более сложной проблемой, потому что, хотя самолет на самом деле летел сквозь море облаков, он летел только в канале, а фон на самом деле представлял собой просто плоскую текстуру, поэтому, когда перспектива достигла определенного уровня. Когда этот уровень будет достигнут, возникнет сильное чувство диссонанса и нереальности, и необходим предел угла обзора, чтобы регулировать угол обзора только в определенном диапазоне.
Ограничения по углу обзора обычно ограничивают глаз и центр g3d. Друзья, которые мало что об этом знают, могут прочитать руководство по 3D на официальном сайте hightopo, где есть подробные инструкции, из-за просмотра я не буду вдаваться в подробности; Диапазон углов, я решил. Чтобы зафиксировать положение центра, код выглядит следующим образом:
g3d.addPropertyChangeListener(e => { // Фиксированная центральная точка if (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = центр[2] }};
Затем ограничьте глаз определенным диапазоном и все готово. Однако здесь не все так просто. Сначала я ограничил глаз кубическим пространством, но эффект взаимодействия был не идеальным, учитывая это в стандартном взаимодействии g3d. , мышь. При перетаскивании и панорамировании для изменения перспективы глаз фактически движется по сферической поверхности с центром в центре, поэтому я решил выкопать из шара часть ограниченного пространства для глаза, которая представляет собой сферический сектор. Для тех, кто плохо понимает, вы можете обратиться к этой картинке:
Для ограничения угла обзора в форме сферического веера требуется всего три параметра, а именно центральная опорная ось, угол между центральной осью и внешним краем и ограниченный радиус шара. Центральная опорная ось может быть определена на основе. Выносная линия, соединяющая начальный глаз и центр, и ограниченный радиус шара разделены на максимальный предел и минимальный предел. Код выглядит следующим образом:
function limitEye(g3d, Eye, Center, Options) { var limitMaxL = options.limitMaxL, limitMinL = options.limitMinL, limitA = options.limitA; g3d.addPropertyChangeListener(e => { // Фиксированная центральная точка if (e.property = == 'центр') { 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(центр), refEyeV = новый ht.Math.Vector3(глаз), refVector = refEyeV.clone().sub(centerV), newVector = newEyeV.clone().sub(centerV); if (centerV.distanceTo(newEyeV) > limitMaxL) { newVector.setLength(limitMaxL); e.newValue[0] = newVector.x; 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); vertVector = newEyeV.clone().sub(refEyeV); vertLength = refLength * Math.tan(limitA); vertVector.setLength(vertLength); realVector = vertVector.clone().add(refEyeV).sub(centerV); .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; )}система мониторинга самолета
Конечно, в качестве системы мониторинга естественно иметь мониторинг. Добавьте небольшую карту в правом нижнем углу и предусмотрите три режима: фокусировка на самолете, фокусировка на траектории полета и фокусировка на карте, а также управление эффектом потока. траектории полета в соответствии с направлением полета самолета. Среди них фокусировка на самолете будет следить за движением самолета и выполнять fitData, чтобы самолет всегда находился в центре мини-карты. Код выглядит следующим образом:
var fitFlowP = function (e) { if (e.property === 'position' && e.data === plane) { mapGV.fitData(plane, false }};buttonP.s({ 'interactive': true, 'onClick': функция (событие, данные, вид, точка, ширина, высота) {map.a('fitDataTag', 'plane2D'); mapDM.md(fitFlowP); }});buttonL.s({ 'interactive': true, 'onClick': функция (событие, данные, вид, точка, ширина, высота) {mapDM.umd(fitFlowP); map. a('fitDataTag', 'flyLine'); mapGV.fitData(flyLine, false }});// ... опущено
Добавлены подсказки по наведению мыши на соответствующее положение самолета для его названия, двойному щелчку мыши для отображения информационной панели соответствующего положения самолета и фокусировке перспективы на панели, щелчку в любом месте самолета для переключения обратно в режим режим полета самолета и другие эффекты.
Добавление панели мониторинга слева заменяет вышеупомянутый двойной щелчок по соответствующей позиции, который непосредственно фокусируется на информационной панели в соответствующей позиции. Кнопка здесь включает взаимодействие и добавляет соответствующую логику взаимодействия. Код выглядит следующим образом:
button_JC.s({ 'interactive': true, 'onClick': функция (событие, данные, вид, точка, ширина, высота) { event.preventDefault(); let g3d = G.g3d, g3dDM = G.g3d.dm (); g3d.fireInteractorEvent({вид: 'doubleClickData', данные: g3dDM.getDataByTag(data.getTag()) }) }});//...опущеноЭффект рендеринга неба
Поскольку это система мониторинга, ее необходимо контролировать 24 часа в сутки без исключения. Это создает проблему. Я не могу летать по голубому небу посреди ночи. Это не соответствует действительности, поэтому должно быть что-то. Процесс перехода неба от светлого к темному, а затем от темного к светлому, я ориентировочно установил этот процесс на два временных периода: 06:00-06:30 и 19:00-19:30.
Небо использует сферическую форму shape3d: 'sphere', чтобы обернуть всю сцену, а затем использоватьverse.flip для обратного копирования и смешивания красителя. После этого небо можно отобразить в цвет, который я хочу. свет и оттенок неба в зависимости от времени, мне нужно только изменить значение красителя.
Однако из-за разных условий освещения днем и ночью интенсивность отраженного от облаков света также различна, что приводит к разнице между облаками днем и ночью. Поэтому также необходимо настроить прозрачность непрозрачности облака. текстуры фона канала и облаков, которые более прозрачны ночью. Код выглядит следующим образом:
if ((час > 6 && час < 19) || (час == 6 && минуты >= 30)) { timePane && timePane.a({ 'morning.visible': false, 'day.visible': true, ' сумрак.видимый': ложь, 'ночь.видимый': ложь, 'день.opacity': 1 }) skyBox.s({ shape3d.blend: 'rgb(127, 200, 240)', }) cloudBackground.s({ back.opacity: 0.7, }) Cloud.s({ shape3d.opacity: 0.7, })} else if ((hour < 6 || час > 19) || (час == 19 && минуты >= 30)) {//... опущено} else if (час == 6 && минуты < 15 ) {//... опущены} else if (час == 6 && минуты >= 15 && минуты < 30) {//... опущены} else if (час == 19 && минуты < 15) { //...Опущено} else if (час == 19 && минут >= 15 && минут < 30) {//...Опущено}
Здесь я также добавил поддержку значка состояния времени в правом верхнем углу панели времени и добавил эффект постепенного появления и исчезновения при переключении значка. В то же время я добавил переключение по щелчку. к следующему положению значка состояния времени для значка состояния панели времени.
Чтобы продемонстрировать эффект, я добавил кнопку удвоения времени. На следующем рисунке показаны изменения при увеличении скорости потока времени в 500 раз:
Подвести итогБлагодаря этой демонстрации я обнаружил, что в жизни есть много деталей, которые люди не замечают, и существует возможность визуализации данных. В эпоху больших данных стоит изучить больше возможностей. Не упускайте ни одной ценной информации. Визуализация деталей вокруг вас может не только лучше раскрыть потенциал HT для Интернета, но и повысить общий уровень профессионализма программиста.