Salas de computadores 3D renderizadas com WebGL não são novidade agora. O objetivo principal deste artigo é explicar o problema do olho e do centro nas salas de computadores 3D, que por acaso foram usadas no projeto. sinto que este exemplo melhor atende às minhas necessidades, então o uso como registro.
renderizaçõesA demonstração desta sala de informática 3D é muito boa, é bonita e as interações básicas são satisfatórias.
geração de código Definir classePrimeiro, abra o js correspondente um por um a partir do caminho js chamado em index.html. Uma classe Editor.Server é customizada em server.js e é criada pela função ht.Default.def encapsulada por HT (observe que a classe criada o nome é Editor O Editor na frente de .Server não pode ser substituído por E):
ht.Default.def('Editor.Server', Object, {//O primeiro parâmetro é o nome da classe. Se for uma string, será automaticamente registrado no classMap do HT; o segundo parâmetro é a classe pai a ser herdada por esta classe; O terceiro parâmetro é a declaração de métodos e variáveis addToDataModel: function(dm) { //Adicione o nó ao contêiner de dados dm.add(this._node); nó por meio de adição Método adicionado ao contêiner de dados}, setHost: function() { //Definir a adsorção this._node.setHost.apply(this._node, argument }, s3: function() {//Definir o tamanho do nó); this._node .s3.apply(this._node, argumentos }, setElevation: function() {//Controle a posição do eixo y do sistema de coordenadas 3D onde a posição central da primitiva Node está localizada this._node.setElevation.apply(this._node, argument }});
Criar classe Editor.Server
Esta classe pode criar um nó ht.Node e definir a cor e a textura frontal do nó:
var S = E.Server = function(obj) {//Componente do servidor var color = obj.color, frontImg = obj.frontImg var node = this._node = new ht.Node();//Criar nó node.s; ({//Defina os estilos do nó para a abreviatura de setStyle 'all.color': color, //Defina a cor dos seis lados do nó 'front.image': frontImg //Define a imagem na frente do nó});};
Desta forma, posso criar diretamente um novo objeto de componente de servidor onde preciso criar o componente de servidor, e posso chamar diretamente setHost e outras funções que declaramos acima, que usaremos em breve.
Em seguida, crie a classe de gabinete Editor.Cabinet. O método é semelhante ao método de definição da classe Editor.Server acima:
ht.Default.def('Editor.Cabinet', Object, { addToDataModel: function(dm) { dm.add(this._door); dm.add(this._node); this._serverList.forEach(função(ões) { s.addToDataModel(dm });, p3: função() { this._node.p3.apply(this._node, argument);//Defina as coordenadas 3D do nó}});
Criar classe Editor.Cabinet
Esta classe é relativamente mais complexa do que a classe de componente de servidor Editor.Server anterior. Esta classe cria um corpo de gabinete, uma porta de gabinete e componentes de servidor dentro do gabinete:
var C = E.Cabinet = function (obj) { var color = obj.color, doorFrontImg = obj.doorFrontImg, doorBackImg = obj.doorBackImg, s3 = obj.s3; ; // Gabinete node.s3(s3); //Defina o tamanho do nó para setSize3d; node.a('cabinet', this);//Personalize as propriedades do gabinete node.s({//Defina o estilo do nó como setStyle 'all.color': color,//Defina a cor dos seis lados do nó 'front.visible ': false // Defina se a frente do nó está visível}); if (Math.random() > 0.5) { node.addStyleIcon('alarm', {//Adicione nomes de ícones ao nó: ['icon termômetro'], //Um array contendo múltiplas strings, cada string corresponde a uma imagem ou vetor (registrado através de ht.Default.setImage) face: 'top', //O valor padrão é frontal, orientação do ícone em 3D , os valores disponíveis são left|right|top|bottom|front|back|center position: 17, //Especifique a posição dos ícones de rotação automática: 'y', //O valor padrão é falso, se o ícone estiver voltado automaticamente para a direção do olho em 3D t3: [0, 16, 0], //O valor padrão é indefinido, o deslocamento do ícone em 3D, o formato é [x, y, z] largura: 37, // Especifique a largura de cada ícone, o padrão é baseado na largura ao registrar a altura da imagem: 32, // Especifique a altura de cada ícone, o padrão é com base na altura ao registrar a imagem TextureScale: 4, //O valor padrão é 2. Este valor representa o múltiplo do mapa real gerado pela memória. Não deve ser definido muito grande, caso contrário afetará o desempenho visível: { func: function() { return !! E.alarmVisible; }}//Indica o grupo de imagens a serem exibidas }); var door = this._door = new. ht.DoorWindow();//Porta do armário door.setWidth(s3[0]);//Definir o comprimento do elemento gráfico na direção do eixo x na topologia 3D door.setHeight(1);//Definir o elemento gráfico no eixo z da topologia 3D em Length door.setTall(s3[1]);//Controla o comprimento da primitiva Node no eixo y door.setElevation(0);//Define a coordenada y do centro da primitiva no sistema de coordenadas 3D door .setY(s3[2] * 0.5);//Definir a posição do nó no eixo y door.setHost(node);//Definir a porta de adsorção.s({//Definir o estilo do nó setStyle 'all.color': color,/ /Definir a cor dos seis lados do nó 'front.image': doorFrontImg, //Definir a imagem frontal do nó 'front.transparent': true, //Definir se a face frontal do nó é transparente 'back .image': doorBackImg, //Defina a imagem na parte de trás do nó 'back.uv': [1,0, 1,1, 0,1, 0,0], // Personalize o mapa UV atrás do nó. Se estiver vazio, o valor padrão [0,0, 0,1, 1,1, 1. ,0] ' dw.axis': 'right' // Define o eixo de rotação para operações de expansão e fechamento do elemento DoorWindow, os valores possíveis são left|right|top|bottom|v|h }); ._serverList = []; max = 6, list = E.randomList(max, Math.floor(Math.random() * (max - 2)) + 2 //Função para obter números aleatórios declarados em global.js var server, h = s3); [0] / 4; list.forEach(function(r) { var server = new E.Server({ //Cor do componente do servidor: 'rgb(51,49,49)', frontImg: 'Componente do servidor fino' }); server.s3(s3[0] - 2, h, s3[2] - 4);//Define o tamanho do nó server.setElevation((r - max * 0.5) * (h + 2 ));//Defina as coordenadas do ponto central do nó no eixo y server.setHost(node);//Defina a adsorção do nó serverList.push(server);//To serverList Adicione o nó do servidor em });};
A única coisa não mencionada no código acima é a função Editor.randomList. Esta função é declarada no arquivo global.js e é declarada da seguinte forma:
var E = window.Editor = { leftWidth: 0, topHeight: 40, randomList: function (max, size) { var list = [], correu while (list.length <tamanho) { correu = Math.floor (Math. random() * max); if (list.indexOf(ran) >= 0) continue list.push(ran);
Ok, agora que as classes para cada parte da cena foram criadas, devemos criar a cena e então empilhar essas primitivas nela!
Criação de cenaOs alunos familiarizados com ele devem saber que usar HT para criar uma cena 3D requer apenas um novo componente 3D e, em seguida, adicionar a cena ao corpo por meio da função addToDOM:
var g3d = E.main = new ht.graph3d.Graph3dView();
O arquivo main.js faz principalmente alguns elementos necessários na cena 3D, como paredes, pisos, portas, condicionadores de ar e as posições de geração e descarga de todos os gabinetes, além de partes interativas muito importantes.
Não vou postar o código para a criação de paredes, pisos, portas, condicionadores de ar e armários. Se você estiver interessado, verifique você mesmo o código. Aqui falamos principalmente sobre clicar duas vezes no gabinete e em quaisquer objetos relacionados ao gabinete (. portas de gabinete, equipamento de servidor) para criar 3D O centro da linha de visão da câmera se moverá para uma determinada posição na frente do gabinete clicado duas vezes, e esse movimento é muito suave antes, então pensei. sobre esta parte por muito tempo e, finalmente, referi-me ao método de implementação desta Demo.
Para poder definir repetidamente eye e center, o conteúdo correspondente à configuração desses dois parâmetros é encapsulado nos métodos setEye e setCenter. O método setCenter é semelhante ao método setEye e não será repetido aqui:
//Definir a posição do olho var setEye = function(eye, finish) { if (!eye) return; - e[0], dy = eye[1] - e[1], dz = eye[2] - e[2] // Inicia uma transição de animação de 500 milissegundos ht.Default.startAnim({ duração: 500, easing: easing,//função de atenuação da animação finishFunc: finish || function() {}, //Função chamada após o término da animação action: function(v, t) {//Define a animação v para representar a atenuação de passagem (t) O valor após a operação da função, t representa o progresso da animação atual [0 ~ 1], as alterações gerais de atributos são baseadas no parâmetro v g3d.setEye([ //Definir o olho na cena 3D O valor do olho é uma matriz, correspondendo aos valores dos eixos x, y e z respectivamente e[0] + dx * v, e[1] + dy * v, e[2] + dz * v ]); } }) ;};
O fato de eu não ter declarado repetidamente a função setCenter não significa que esta função não seja importante. Pelo contrário, esta função desempenha um papel decisivo no processo de movimentação da linha de visão. A função setEye acima é equivalente a eu querer. andar na frente da minha posição alvo (pelo menos eu defino que é usado para esse propósito), enquanto o sCenter A definição é mover minha visão para a posição do alvo (por exemplo, posso ficar na minha posição atual e olhar para o objeto atrás de mim à direita, ou posso ir para trás à minha direita e ficar na frente de o objeto para olhar para ele). É muito importante, por favor, saboreie.
O evento de clique duplo é simples. Basta ouvir o evento encapsulado pelo HT, determinar o tipo de evento e executar as ações correspondentes:
g3d.mi(function(e) {//addInteractorListener função de escuta de evento if (e.kind !== 'doubleClickData') //Determina o tipo de evento como um nó de clique duplo return; var data = e.data, p3 ; if (data. a('cabinet')) //Body p3 = data.p3(); else { host = data.getHost(); host.a('cabinet')) {//Se o objeto de adsorção for gabinete p3 = host.p3(); if (!p3) return; posição do gabinete setEye([p3[0], 211, p3[2] + 247] //Define a posição onde o olho se moverá});barra de navegação superior
Quando vi este exemplo pela primeira vez, pensei: essa pessoa é tão incrível que uso o HT há muito tempo, mas ainda não consegui criar efeitos tão bonitos usando o ht.widget.Toolbar do HT. nisso, percebi que na verdade estava usando HT. É feito com forma, é incrível, sou tão estúpido.
var formulário = E.top = new ht.widget.FormPane(); //Componente superior do formulário form.setRowHeight(E.topHeight);//Defina a altura da linha form.setVGap(-E.topHeight);//Defina o espaçamento horizontal do componente do formulário para um valor negativo da altura da linha para manter múltiplas linhas na mesma posição Linha form.setVPadding(0);//Define o topo do formulário e o espaçamento entre o topo e o conteúdo do componente form.addRow([null, {//Adicione uma linha de componentes ao formulário. O primeiro parâmetro é uma matriz de elementos. Os elementos podem ser strings, informações de parâmetro de componente descritas em formato json, elementos html ou imagem nula: { icon: './symbols/ inputBG.json ', trecho: 'centerUniform' }}], [40, 260]);//O segundo parâmetro é uma matriz de informações de largura para cada elemento. Um valor de largura maior que 1 representa um valor absoluto fixo, e um valor de largura menor ou igual a 1 representa um valor relativo. uma combinação de 80+0,3 form.addRow([null, null , { id: 'searchInput', textField: {}}, { element: 'Sistema de gerenciamento visual de sala de computadores', cor: 'branco', fonte: '18px arial , sem serifa'}, nulo, { botão: { // rótulo: 'ViewChange', ícone: './symbols/viewChange.json', plano de fundo: nulo, selectBackground: 'rgb(128,128,128)', borderColor: 'rgba(0, 0, 0, 0 ) ', onClicked: function() { E.focusTo() }}, null, { button: { // label: 'Alerta', ícone: './symbols/alarm.json', alternável: verdadeiro, selecionado: falso, plano de fundo: nulo, selectBackground: 'rgb(128,128,128)', borderColor: 'rgba(0, 0, 0, 0)', onClicked: function( e) { E.setAlarmVisible(this.isSelected()); 42, 218, 300, 0,1, 50, 10, 50, 10]);
O acima só é possível, mas na verdade não é adicionado à tag html, o que significa que não há nada na interface agora! Não se esqueça de adicionar a cena 3D ao corpo quando a página carregar, e não se esqueça de adicionar o formulário ao corpo Ao definir o evento de alteração do tamanho da janela, o formulário também precisa ser atualizado em tempo real:
window.addEventListener('load', function() { g3d.addToDOM(); //Adiciona a cena 3D ao corpo document.body.appendChild(E.top.getView()); //Adiciona a div subjacente do componente de formulário Adicionar ao corpo window.addEventListener('resize', function() {//Ouvir eventos de mudança de tamanho da janela E.top.iv();//Atualizar o div subjacente do formulário form });});
Aqui está uma explicação da função addToDOM, que é muito importante para a compreensão do mecanismo do HT. Os componentes HT geralmente são incorporados em contêineres como BorderPane, SplitView e TabView. O componente HT mais externo requer que o usuário adicione manualmente o elemento div subjacente retornado por getView() ao elemento DOM da página. , Quando o tamanho do contêiner pai muda, se o contêiner pai for um componente de contêiner predefinido do HT, como BorderPane e SplitView, o contêiner HT chamará automaticamente a função invalidate do componente filho recursivamente para notificar a atualização. Mas se o contêiner pai for um elemento html nativo, o componente HT não pode saber que precisa ser atualizado. Portanto, o componente HT mais externo geralmente precisa ouvir o evento de alteração do tamanho da janela e chamar a função de invalidação do mais externo. componente a ser atualizado.
Para facilitar o carregamento do componente mais externo para preencher a janela, todos os componentes do HT possuem a função addToDOM, e sua lógica de implementação é a seguinte, onde iv é a abreviatura de invalidate:
addToDOM = function(){ var self = this, view = self.getView(), style = view.style; document.body.appendChild(view); ' 0';//HT define a posição do div subjacente de todos os componentes para absoluto style.right = '0'; window.addEventListener('resize', function () { self.iv(); }, false); //Ouvir eventos para alterações no tamanho da janela e notificar alterações e atualizações de componentes}
Desta forma, todo o código acabou. Você pode clicar com o botão direito para verificar você mesmo e o arquivo json correspondente pode ser obtido na rede.
O texto acima é todo o conteúdo deste artigo. Espero que seja útil para o estudo de todos. Também espero que todos apoiem a Rede VeVb Wulin.