Eu estava em viagem de negócios há alguns dias e vi o painel de monitoramento aéreo do avião, além de passar séries de TV e anúncios, ele também mudava de vez em quando para um sistema de monitoramento de navegação de aeronaves. O sistema parecia um pouco rudimentar, então, por capricho, fiz uma versão atualizada do sistema de monitoramento usando HT para Web. A demonstração é muito boa, então gostaria de compartilhá-la com vocês para que possamos aprender uns com os outros.
demonstração
Processo de implementaçãoCaminhando pelo efeito das nuvens
Para obter o efeito de um avião voando através das nuvens, o primeiro problema que encontrei foi a estratificação do voo do avião, comumente conhecido como efeito de perspectiva. Aqui usei o canal de nuvem e o fundo da nuvem para fluir em velocidades diferentes. para criar um efeito de perspectiva voadora.
Apresentei as nuvens na forma de texturas, mas apenas as texturas bloqueariam o céu e a aeronave, o que afetaria muito a aparência da aeronave voando, então ativei a transparência e a opacidade dos elementos gráficos correspondentes, e defina diferentes níveis de transparência para o fundo da nuvem e o canal da nuvem. Isso não apenas adiciona uma sensação de camadas, mas também dá às pessoas a ilusão de nuvens passando diante de seus olhos.
O canal de nuvem usa o tipo ht.Polyline. A escala do canal aumenta a proporção do eixo Y, dando ao canal de nuvem um espaço vertical maior. Definir a cópia reversa.flip permite que a textura seja exibida dentro do canal de nuvem. se a aeronave estiver no ar. Viajando pelo mar de nuvens; o fundo da nuvem adota o tipo ht.Node e apenas uma superfície é configurada para ser exibida como fundo da nuvem.
O efeito geral do fluxo da nuvem é obtido usando o deslocamento de deslocamento, e o deslocamento da textura do primitivo correspondente ou da superfície primitiva correspondente é alterado para obter o efeito de um avião viajando através das nuvens.
var i = 1, p = 0;setInterval(() => { i -= 0,1; p += 0,005; nuvens.s('shape3d.uv.offset', [i, 0]); cloudBackground.s(' all.uv.offset', [p, 0]);}, 100);
Efeito de colisão de levantamento
Embora consiga o efeito de um avião voando através das nuvens, se o avião voar apenas em linha reta, também reduzirá a sensação real de voar. Acredito que amigos que voaram em um avião devem ter encontrado turbulência causada pelo fluxo de ar, e muitas vezes. sentir a turbulência causada pelo vôo do avião A subida e descida no caminho ocorre porque a rota da aeronave nem sempre é fixa em uma determinada altitude. Às vezes ela sobe e às vezes desce, então usei o plug de extensão de animação HT ht-animation.js
-in para obter o efeito acidentado da aeronave. O código é o seguinte:
dm.enableAnimation(20);plane.setAnimation({ back1: { from: 0, to: 160, easing: 'Cubic.easeInOut', duração: 8000, next: up1, onUpdate: function (value) { value = parseInt( valor); var p3 = isto.p3(); isto.p3(valor, p3[1], p3[2]); }, //...Omitir início semelhante: [back1]});Restrições de ângulo de visão do setor esférico
Depois que o efeito de vôo foi aperfeiçoado, encontrei um problema mais difícil, porque embora o avião estivesse realmente voando através do mar de nuvens, ele estava voando apenas no canal, e o fundo era na verdade apenas uma textura plana, então quando o a perspectiva atingiu um certo nível. Quando este nível for atingido, haverá uma forte sensação de dissonância e irrealidade, e um limite de ângulo de visão é necessário para fazer o ajuste do ângulo de visão dentro de um determinado intervalo.
As restrições de ângulo de visão geralmente limitam o olho e o centro do g3d. Amigos que não sabem muito sobre isso podem ler o manual 3D no site oficial do hightopo, que contém instruções detalhadas, não entrarei em detalhes aqui. faixa de ângulo, decidi fixar a posição do centro, o código é o seguinte:
g3d.addPropertyChangeListener(e => { // Ponto central fixo if (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = centro[2] }}
Em seguida, limite o olho a um determinado intervalo e pronto. No entanto, não é tão simples aqui. No início, limitei o olho a um espaço cúbico, mas o efeito de interação não foi o ideal. , o mouse Ao arrastar e deslocar para mudar a perspectiva, o olho na verdade se move em uma superfície esférica com o centro como centro, então decidi cavar um pedaço de espaço restrito para o olho na bola, que é um setor esférico. Para quem não entende bem Você pode consultar esta imagem:
O limite do ângulo de visão em forma de leque esférico requer um total de três parâmetros, nomeadamente o eixo de referência central, o ângulo entre o eixo central e a borda externa e o raio limitado da bola. linha de extensão conectando o olho inicial e o centro, e o raio limitado da bola está localizado. É dividido em limite máximo e limite mínimo.
function limitEye(g3d, eye, center, options) { var limitMaxL = options.limitMaxL, limitMinL = options.limitMinL, limitA = g3d.addPropertyChangeListener(e => { // Ponto central fixo if (e.property = == 'centro') { e.newValue[0] = centro[0]; e.newValue[2] = center[2] } // Limita o ângulo de visão if (e.property === 'eye') { var newEyeV = new ht.Math.Vector3(e.newValue), centerV = new ht.Math.Vector3(centro), refEyeV = novo ht.Math.Vector3(olho), refVector = refEyeV.clone().sub(centerV), newVector = newEyeV.clone().sub(centerV); if (centerV.distanceTo(newEyeV) > limitMaxL) { newVector.setLength(limitMaxL); novoVetor.y; e.newValue[2] = novoVetor.z } if (centerV.distanceTo(newEyeV) < limitMinL) { newVector.setLength(limitMinL); e.newValue[0] = newVector.x; refVector) > limitA) { var oldLength = newVector.length(), oldAngle = newVector.angleTo(refVector), refLength = oldLength * Math.cos (oldAngle), vertVector, realVector, realEye; refVector.setLength (refLength) = newVector.clone().add(centerV); vertVector = newEyeV.clone().sub(refEyeV); vertLength = refLength * Math.tan(limitA);realVector.setLength(oldLength); .add(centerV); // Evita que o ângulo de movimento seja maior que 180 graus e inverte a perspectiva if (oldAngle > Math.PI / 2) { realEye.negate(); e.newValue[0] = realEye.x; )}sistema de monitoramento de aeronaves
Claro, como sistema de monitoramento, é natural adicionar um pequeno mapa no canto inferior direito e fornecer três modos: foco na aeronave, foco na trajetória de vôo e foco no mapa, e controle do efeito de fluxo. da trajetória de voo de acordo com a direção de voo da aeronave. Entre eles, focar na aeronave irá acompanhar o movimento da aeronave e realizar fitData para que a aeronave fique sempre no centro do minimapa.
var fitFlowP = function (e) { if (e.property === 'posição' && e.data === plano) { mapGV.fitData(plano, false }};buttonP.s({ 'interativo': true, 'onClick': função (evento, dados, visualização, ponto, largura, altura) { map.a('fitDataTag', 'mapGV.fitData(plane, false); mapDM.md(fitFlowP }});buttonL.s({ 'interativo': true, 'onClick': função (evento, dados, visualização, ponto, largura, altura) { mapDM.umd(fitFlowP); mapa. a('fitDataTag', 'flyLine'); mapGV.fitData(flyLine, false }});// ...omitido
Adicionados prompts para mover o mouse até a posição correspondente da aeronave para nomeá-la, clicar duas vezes para exibir o painel de informações da posição correspondente da aeronave e focar a perspectiva no painel, clicar em qualquer lugar da aeronave para voltar ao modo de vôo da aeronave e outros efeitos.
Adicionar um painel de monitoramento à esquerda substitui o clique duplo mencionado acima na posição correspondente, que foca diretamente no painel de informações na posição correspondente. O botão aqui permite a interação e adiciona a lógica de interação correspondente.
button_JC.s({ 'interativo': true, 'onClick': função (evento, dados, visualização, ponto, largura, altura) { event.preventDefault(); deixe g3d = G.g3d, g3dDM = G.g3d.dm (); g3d.fireInteractorEvent({ tipo: 'doubleClickData', dados: g3dDM.getDataByTag(data.getTag()) }) }});//...omitidoEfeito de renderização do céu
Por ser um sistema de monitoramento, deve ser monitorado 24 horas por dia sem distinção. Isso envolve um problema. É impossível para mim voar sobre o céu azul no meio da noite. O processo do céu do claro para o escuro e depois do escuro para o claro, defini provisoriamente esse processo para os dois períodos de tempo de 06h00-06h30 e 19h00-19h30.
O céu usa uma forma esférica shape3d: 'esfera' para envolver toda a cena e, em seguida, use reverse.flip para copiar e misturar o corante. Depois disso, o céu pode ser renderizado na cor desejada. luz e sombra do céu de acordo com o tempo, só preciso alterar o valor do corante.
Porém, devido às diferentes condições de iluminação entre o dia e a noite, a intensidade da luz refletida das nuvens também é diferente, o que leva à diferença entre as nuvens durante o dia e a noite. Portanto, também é necessário ajustar a opacidade e transparência da nuvem. texturas de fundo de canal e nuvem, que são mais transparentes à noite. O código é o seguinte:
if ((hora > 6 && hora < 19) || (hora == 6 && minutos >= 30)) { timePane && timePane.a({ 'morning.visible': false, 'day.visible': true, ' crepúsculo.visível': falso, 'noite.visível': falso, 'dia.opacidade': 1 }) skyBox.s({ shape3d.blend: 'rgb (127, 200, 240)', }) cloudBackground.s ({ back.opacity: 0,7, }) clouds.s ({ shape3d.opacity: 0,7, })} else if ((hora < 6 || hora > 19) || (hora == 19 && minutos >= 30)) {//...omitido} else if (hora == 6 && minutos < 15 ) {//...omitido} else if (hora == 6 && minutos >= 15 && minutos < 30) {//...omitido} else if (hora == 19 && minutos < 15) { //...Omitido} else if (hora == 19 && minutos >= 15 && minutos < 30) {//...Omitido}
Aqui também adicionei suporte para o ícone de status de hora no canto superior direito do painel de hora e adicionei um efeito de aumento e diminuição gradual quando o ícone é alternado. Ao mesmo tempo, adicionei um clique para alternar. para a próxima posição do ícone de status do ícone de status do painel de tempo.
Para demonstrar o efeito, adicionei um botão de duplicação de tempo. A imagem a seguir mostra as alterações em 500 vezes a taxa de fluxo de tempo:
ResumirAtravés desta demonstração, descobri que existem muitos detalhes na vida que não foram percebidos pelas pessoas, e existe a possibilidade de visualização de dados. Nesta era de big data, vale a pena explorar mais possibilidades. ao seu redor. Visualizar detalhes pode não apenas aproveitar melhor o potencial do HT para Web, mas também fortalecer a qualidade geral de alguém como programador.