Las salas de computadoras 3D renderizadas con WebGL no son nada nuevo ahora. El objetivo principal de este artículo es explicar el problema del ojo y el centro en las salas de computadoras 3D, que se usaron en el proyecto. Creo que este ejemplo cumple mejor con mis requisitos, así que lo uso como registro.
representacionesLa demostración de esta sala de computadoras en 3D es bastante buena, bonita y las interacciones básicas son satisfactorias. Veamos cómo implementarla.
generación de código Definir clasePrimero, abra los js correspondientes uno por uno desde la ruta js llamada en index.html. Una clase Editor.Server se personaliza en server.js y se crea mediante la función ht.Default.def encapsulada por HT (tenga en cuenta que la clase creada). El nombre es Editor. El Editor delante de .Server no se puede reemplazar con E):
ht.Default.def('Editor.Server', Object, {//El primer parámetro es el nombre de la clase. Si es una cadena, se registrará automáticamente en el classMap de HT; el segundo parámetro es la clase principal que se heredará por esta clase. ; El tercer parámetro es la declaración de métodos y variables addToDataModel: function(dm) { //Agrega el nodo al contenedor de datos dm.add(this._node); nodo a través de agregar Método agregado al contenedor de datos}, setHost: function() { //Establece la adsorción this._node.setHost.apply(this._node, arguments }, s3: function() {//Establece el tamaño del nodo); this._node .s3.apply(this._node, argumentos }, setElevation: función()); {//Controlar la posición del eje y del sistema de coordenadas 3D donde se encuentra la posición central de la primitiva Nodo this._node.setElevation.apply(this._node, arguments }});
Crear clase Editor.Server
Esta clase puede crear un nodo ht.Node y establecer el color y la textura frontal del nodo:
var S = E.Server = function(obj) {//Componente del servidor var color = obj.color, frontImg = obj.frontImg; var node = this._node = new ht.Node();//Crear nodo node.s ({//Establezca los estilos del nodo con la abreviatura de setStyle 'all.color': color,//Establezca el color de los seis lados del nodo 'front.image': frontImg //Establece la imagen en el frente del nodo});};
De esta manera, puedo crear directamente un nuevo objeto de componente de servidor donde necesito crear el componente de servidor, y puedo llamar directamente a setHost y otras funciones que declaramos anteriormente, que usaremos pronto.
A continuación, cree la clase de gabinete Editor.Cabinet. El método es similar al método de definición de la clase Editor.Server anterior:
ht.Default.def('Editor.Cabinet', Objeto, { addToDataModel: function(dm) { dm.add(this._door); dm.add(this._node); this._serverList.forEach(function(s) { s.addToDataModel(dm); } }, p3: función() { this._node.p3.apply(this._node, arguments);//Establece las coordenadas 3d del nodo}});
Crear clase Editor.Cabinet
Esta clase es relativamente más compleja que la clase de componente de servidor Editor.Server anterior. Esta clase crea un cuerpo de gabinete, una puerta de gabinete y componentes de servidor dentro del gabinete:
var C = E.Cabinet = function(obj) { var color = obj.color, doorFrontImg = obj.doorFrontImg, doorBackImg = obj.doorBackImg, s3 = obj.s3 var nodo = this._node = new ht.Node(); ; // Cabinet node.s3(s3); //Establece el tamaño del nodo en setSize3d; node.a('cabinet', this);//Personaliza las propiedades del gabinete node.s({//Establece el estilo del nodo en setStyle 'all.color': color,//Establece el color de los seis lados del nodo 'front.visible ': false//Establece si el frente del nodo es visible}); if (Math.random() > 0.5) { node.addStyleIcon('alarm', {//Agrega nombres de iconos al nodo: ['icon thermometer'], //Una matriz que contiene múltiples cadenas, cada cadena corresponde a una imagen o vector (registrado a través de ht.Default.setImage) face: 'top', //El valor predeterminado es front, icon Orientación en 3D , los valores disponibles son izquierda|derecha|arriba|abajo|frente|atrás|posición central: 17, //Especifique la posición de los iconos de rotación automática: 'y', //El valor predeterminado es falso, si el ícono mira automáticamente en la dirección del ojo en 3D t3: [0, 16, 0], //El valor predeterminado no está definido, el desplazamiento del ícono en 3D, el formato es [x, y,z] ancho: 37,// Especifique el ancho de cada ícono, el valor predeterminado se basa en el ancho al registrar la altura de la imagen: 32,// Especifique la altura de cada ícono, el valor predeterminado es basado en la altura al registrar la imagen TextureScale: 4, // El valor predeterminado es 2. Este valor representa el múltiplo del mapa real generado por la memoria. No debe establecerse demasiado grande, de lo contrario afectará el rendimiento visible: { func: function() { return !! E.alarmVisible; }}// Indica si se muestran el grupo de imágenes } } var door = this._door = new. ht.DoorWindow();//Puerta del gabinete door.setWidth(s3[0]);//Establezca la longitud del elemento gráfico en la dirección del eje x en la topología 3D door.setHeight(1);//Establezca el elemento gráfico en la topología 3D eje z en Longitud door.setTall(s3[1]);//Controla la longitud de la primitiva Nodo en el eje y door.setElevation(0);//Establece la coordenada y del centro de la primitiva en la puerta del sistema de coordenadas 3D .setY(s3[2] * 0.5);//Establece la posición del nodo en el eje y door.setHost(node);//Establece la puerta de adsorción.s({//Establece el estilo del nodo setStyle 'all.color': color,/ /Establece el color de los seis lados del nodo 'front.image': doorFrontImg, //Establece la imagen frontal del nodo 'front.transparent': true, //Establece si la cara frontal del nodo es transparente 'back .image': doorBackImg, //Establece la imagen en la parte posterior del nodo 'back.uv': [1,0, 1,1, 0,1, 0,0],//Personaliza el mapa uv detrás del nodo. Si está vacío, el valor predeterminado es [0,0, 0,1, 1,1, 1. ,0] ' dw.axis': 'right'//Establece el eje de rotación para las operaciones de expansión y cierre del elemento DoorWindow, los valores posibles son left|right|top|bottom|v|h }); ._listadeservidores = []; max = 6, list = E.randomList(max, Math.floor(Math.random() * (max - 2)) + 2 //Función para obtener números aleatorios declarados en el servidor var global.js, h = s3); [0] / 4; list.forEach(function(r) { var server = new E.Server({ //Color del componente del servidor: 'rgb(51,49,49)', frontImg: 'Componente del servidor bien' }); server.s3(s3[0] - 2, h, s3[2] - 4);//Establece el tamaño del nodo server.setElevation((r - max * 0.5) * (h + 2 ));//Establezca las coordenadas del punto central del nodo en el eje y server.setHost(node);//Establezca la adsorción del nodo serverList.push(server);//A serverList Agregar nodo de servidor en });};
Lo único que no se menciona en el código anterior es la función Editor.randomList. Esta función se declara en el archivo global.js y se declara de la siguiente manera:
var E = window.Editor = { leftWidth: 0, topHeight: 40, randomList: function(max, size) { var list = [], corrió mientras (list.length < tamaño) { ran = Math.floor(Math. aleatorio() * max); si (list.indexOf(ran) >= 0) continuar; list.push(ran } devolver lista }};
Bien, ahora que se han creado las clases para cada parte de la escena, ¡debemos crear la escena y luego agrupar estas primitivas en ella!
Creación de escenasLos estudiantes que estén familiarizados con él deben saber que usar HT para crear una escena 3D solo requiere un nuevo componente 3D y luego agregar la escena al cuerpo mediante la función addToDOM:
var g3d = E.main = new ht.graph3d.Graph3dView(); //escena 3d
El archivo main.js realiza principalmente algunos elementos necesarios en la escena 3D, como paredes, pisos, puertas, aires acondicionados y las posiciones de generación y descarga de todos los gabinetes, así como partes interactivas muy importantes.
No publicaré el código para la creación de paredes, pisos, puertas, aires acondicionados y gabinetes. Si está interesado, verifique el código usted mismo. Aquí hablamos principalmente de hacer doble clic en el gabinete y cualquier objeto relacionado con el gabinete (. puertas de gabinetes, equipos de servidores) para crear 3D. El centro de la línea de visión de la cámara se moverá a una determinada posición frente al gabinete en el que se hace doble clic, y este movimiento es muy suave. No era bueno en eso antes, así que pensé. Sobre esta parte durante mucho tiempo, y finalmente me refiero al método de implementación de esta demostración.
Para poder configurar el ojo y el centro repetidamente, el contenido correspondiente a la configuración de estos dos parámetros se encapsula en los métodos setEye y setCenter. El método setCenter es similar al método setEye y no se repetirá aquí:
//Establece la posición del ojo var setEye = function(eye, Finish) { if (!eye) return; g3d.getEye().slice(0),//Obtiene el valor actual del ojo dx = eye[0] - e[0], dy = eye[1] - e[1], dz = eye[2] - e[2] // Inicia una transición de animación de 500 milisegundos ht.Default.startAnim({ duración: 500, aceleración: aceleración, // Función de aceleración de animación FinishFunc: terminar || función() {}, //Función llamada después de que finaliza la animación acción: función(v, t) {//Establecer animación v para representar la aceleración de paso (t) El valor después de la operación de la función, t representa el progreso de la animación actual [0 ~ 1], los cambios de atributos generales se basan en el parámetro v g3d.setEye([ //Establece el ojo en la escena 3D El valor del ojo es una matriz, correspondiente a los valores de los ejes x, y y z respectivamente e[0] + dx * v, e[1] + dy * v, e[2] + dz * v ]); } }) ;};
El hecho de que no haya declarado repetidamente la función setCenter no significa que esta función no sea importante. Por el contrario, esta función juega un papel decisivo en el proceso de mover la línea de visión. La función setEye anterior es equivalente a querer. caminar frente a mi posición objetivo (al menos yo defino que se usa para este propósito), mientras que sCenter La definición es mover mi vista a la posición del objetivo (por ejemplo, puedo pararme en mi posición actual y mirar el objeto detrás de mí a la derecha, o puedo ir hacia atrás a mi derecha y pararme frente a él). el objeto para mirarlo). Es muy importante, por favor saboréalo.
El evento de doble clic es simple: simplemente escuche el evento encapsulado por HT, determine el tipo de evento y tome las acciones correspondientes:
g3d.mi(function(e) {//addInteractorListener función de escucha de eventos if (e.kind !== 'doubleClickData') //Determina que el tipo de evento será un retorno de nodo de doble clic; var data = e.data, p3 ; if (data. a('cabinet')) //Body p3 = data.p3(); else { host = data.getHost() //Obtiene el objeto de adsorción del nodo seleccionado if (host &&) host.a('cabinet')) {//Si el objeto de adsorción es gabinete p3 = host.p3(); } } if (!p3) return; setCenter(p3); posición del gabinete setEye([p3[0], 211, p3[2] + 247] //Establece la posición donde se moverá el ojo});barra de navegación superior
Cuando vi este ejemplo por primera vez, pensé: esta persona es increíble. He estado usando HT durante tanto tiempo, pero todavía no he podido crear efectos tan hermosos usando ht.widget.Toolbar de HT. Al verlo, me di cuenta de que en realidad estaba usando HT. Está hecho con forma, es increíble, soy tan estúpido.
var formulario = E.top = nuevo ht.widget.FormPane(); //Componente del formulario superior form.setRowHeight(E.topHeight);//Establece la altura de la fila form.setVGap(-E.topHeight);//Establece el espaciado horizontal del componente del formulario en un valor negativo de la altura de la fila para mantener varias filas en la misma posición Line form.setVPadding(0);//Establezca la parte superior del formulario y el espacio entre la parte superior y el contenido del componente form.addRow([null, {//Agregue una fila de componentes al formulario. El primer parámetro es una matriz de elementos. Los elementos pueden ser cadenas, información de parámetros de componentes descrita en formato json, elementos html o imagen nula: { icon: './symbols/. inputBG.json ', estiramiento: 'centerUniform' }}], [40, 260]);// El segundo parámetro es una matriz de información de ancho para cada elemento. Un valor de ancho mayor que 1 representa un valor absoluto fijo, y un valor de ancho menor o igual a 1 representa un valor relativo. una combinación de 80+0,3 form.addRow([null, null, { id: 'searchInput', textField: {}}, { elemento: 'Sistema de gestión visual de la sala de ordenadores', color: 'blanco', fuente: '18px arial , sans-serif'}, nulo, { botón: { // etiqueta: 'ViewChange', icono: './symbols/viewChange.json', fondo: nulo, selectBackground: 'rgb(128,128,128)', borderColor: 'rgba(0, 0, 0, 0) ', onClicked: function() { E.focusTo() } }}, null, { botón: { // etiqueta: 'Alerta', icono: './symbols/alarm.json', alternable: verdadero, seleccionado: falso, fondo: nulo, selectBackground: 'rgb(128,128,128)', borderColor: 'rgba(0, 0, 0, 0)', onClicked: function( e) { E.setAlarmVisible(this.isSelected()); } }}, nulo], [40, 42, 218, 300, 0,1, 50, 10, 50, 10]);
Lo anterior solo es posible, pero en realidad no se agrega a la etiqueta html, lo que significa que ahora no hay nada en la interfaz. No olvide agregar la escena 3D al cuerpo cuando se carga la página y no olvide agregar el formulario al cuerpo al configurar el evento de cambio de tamaño de la ventana, el formulario también debe actualizarse en tiempo real:
window.addEventListener('load', function() { g3d.addToDOM(); //Agrega la escena 3D al cuerpo document.body.appendChild(E.top.getView()); //Agrega el div subyacente del componente de formulario Agregar al cuerpo window.addEventListener('resize', function() {//Escuche los eventos de cambio de tamaño de la ventana E.top.iv();//Actualice el div subyacente del formulario });});
Aquí hay una explicación de la función addToDOM, que es muy importante para comprender el mecanismo de HT. Los componentes HT generalmente están integrados en contenedores como BorderPane, SplitView y TabView. El componente HT más externo requiere que el usuario agregue manualmente el elemento div subyacente devuelto por getView () al elemento DOM de la página. , Cuando cambia el tamaño del contenedor principal, si el contenedor principal son los componentes de contenedor predefinidos de HT, como BorderPane y SplitView, el contenedor HT llamará automáticamente a la función de invalidación del componente secundario de forma recursiva para notificar la actualización. Pero si el contenedor principal es un elemento html nativo, el componente HT no puede saber que necesita ser actualizado. Por lo tanto, el componente HT más externo generalmente necesita escuchar el evento de cambio de tamaño de la ventana y llamar a la función de invalidación del más externo. componente a actualizar.
Para facilitar la carga del componente más externo para llenar la ventana, todos los componentes de HT tienen la función addToDOM y su lógica de implementación es la siguiente, donde iv es la abreviatura de invalidar:
addToDOM = function(){ var self = this, view = self.getView(), style = view.style; document.body.appendChild(view); agrega el div subyacente de la escena al cuerpo style.left = ' 0';//HT establece la posición del div subyacente de todos los componentes en absoluto style.right = '0'; window.addEventListener('resize', function () { self.iv(); }, false); //Escucha eventos para cambios en el tamaño de la ventana y notifica cambios y actualizaciones de componentes}
De esta manera, todo el código ha terminado. Puede hacer clic derecho para verificarlo usted mismo y podrá obtener el archivo json correspondiente de la red.
Lo anterior es el contenido completo de este artículo. Espero que sea útil para el estudio de todos. También espero que todos apoyen VeVb Wulin Network.