Mit WebGL gerenderte 3D-Computerräume sind nichts Neues. Der Hauptzweck dieses Artikels besteht darin, das Problem des Auges und der Mitte in 3D-Computerräumen zu erklären, die zufällig im Projekt verwendet wurden Ich bin der Meinung, dass dieses Beispiel meinen Anforderungen am besten entspricht, daher verwende ich es als Aufzeichnung.
DarstellungenDie Demo dieses 3D-Computerraums ist ziemlich gut, sie ist hübsch und die grundlegenden Interaktionen sind zufriedenstellend. Mal sehen, wie man sie umsetzt.
Codegenerierung Klasse definierenÖffnen Sie zunächst die entsprechenden js nacheinander aus dem in index.html aufgerufenen js-Pfad. Eine Editor.Server-Klasse wird in server.js angepasst und durch die von HT gekapselte Funktion ht.Default.def erstellt (beachten Sie, dass die erstellte Klasse Name ist Editor Der Editor vor .Server kann nicht durch E ersetzt werden):
ht.Default.def('Editor.Server', Object, {//Der erste Parameter ist der Klassenname. Wenn es sich um eine Zeichenfolge handelt, wird sie automatisch in der ClassMap von HT registriert. Der zweite Parameter ist die zu vererbende übergeordnete Klasse von dieser Klasse. ; Der dritte Parameter ist die Deklaration von Methoden und Variablen addToDataModel: function(dm) { //Den Knoten zum Datencontainer hinzufügen dm.add(this._node); Knoten durch add Dem Datencontainer hinzugefügte Methode}, setHost: function() { //Legen Sie die Adsorption fest this._node.setHost.apply(this._node, arguments); }, s3: function() {//Legen Sie die Größe des Knotens fest this._node .s3.apply(this._node, arguments); }, setElevation: function() {//Steuern Sie die y-Achsenposition des 3D-Koordinatensystems, wo sich die Mittelposition des Node-Grundelements befindet this._node.setElevation.apply(this._node, arguments }});
Erstellen Sie die Editor.Server-Klasse
Diese Klasse kann einen ht.Node-Knoten erstellen und die Farbe und Fronttextur des Knotens festlegen:
var S = E.Server = function(obj) {//Serverkomponente var color = obj.color, frontImg = obj.frontImg; var node = this._node = new ht.Node();//Knoten erstellen node.s ({//Setzen Sie die Stile des Knotens auf die Abkürzung von setStyle 'all.color': color,//Setzen Sie die Farbe der sechs Seiten des Knotens 'front.image': frontImg //Setze das Bild auf die Vorderseite des Knotens});};
Auf diese Weise kann ich direkt ein neues Serverkomponentenobjekt erstellen, an dem ich die Serverkomponente erstellen muss, und ich kann setHost und andere oben deklarierte Funktionen direkt aufrufen, die wir bald verwenden werden.
Als nächstes erstellen Sie die Schrankklasse Editor.Cabinet. Die Methode ähnelt der Definitionsmethode der obigen Klasse Editor.Server:
ht.Default.def('Editor.Cabinet', Object, { addToDataModel: function(dm) { dm.add(this._door); dm.add(this._node); this._serverList.forEach(function(s) { s.addToDataModel(dm }); p3: function() { this._node.p3.apply(this._node, arguments);//Legen Sie die 3D-Koordinaten des Knotens fest}});
Erstellen Sie die Editor.Cabinet-Klasse
Diese Klasse ist relativ komplexer als die vorherige Serverkomponentenklasse Editor.Server. Diese Klasse erstellt einen Schrankkörper, eine Schranktür und Serverkomponenten im Schrank:
var C = E.Cabinet = function(obj) { var color = obj.color, doorFrontImg = obj.doorFrontImg, doorBackImg = obj.doorBackImg, s3 = obj.s3; var node = this._node = new ht.Node() ; // Cabinet node.s3(s3); //Setzen Sie die Größe des Knotens auf setSize3d node.a('cabinet', this);//Anpassen der Schrankeigenschaften node.s({//Setzen Sie den Knotenstil auf setStyle 'all.color': color,//Legen Sie die Farbe der sechs Seiten des Knotens fest 'front.visible ': false//Legen Sie fest, ob die Vorderseite des Knotens sichtbar ist}); if (Math.random() > 0.5) { node.addStyleIcon('alarm', {//Symbolnamen zum Knoten hinzufügen: ['icon Thermometer'], // Ein Array mit mehreren Zeichenfolgen, jede Zeichenfolge entspricht einem Bild oder Vektor (registriert über ht.Default.setImage) face: 'top', // Der Standardwert ist front, Symbolausrichtung in 3D , verfügbare Werte sind left|right|top|bottom|front|back|center position: 17, //Geben Sie die Position der Symbole an. Autorotate: 'y', // Der Standardwert ist falsch, ob das Symbol in 3D automatisch in die Richtung des Auges zeigt. t3: [0, 16, 0], // Der Standardwert ist undefiniert, der Versatz des Symbols in 3D, Das Format ist [x, y, z], Breite: 37, // Geben Sie die Breite jedes Symbols an. Der Standardwert basiert auf der Breite bei der Registrierung der Bildhöhe: 32, // Geben Sie die Höhe jedes Symbols an. Der Standardwert ist basierend auf der Höhe bei der Registrierung der BildtexturScale: 4, // Der Standardwert ist 2. Dieser Wert stellt das Vielfache der tatsächlich vom Speicher generierten Karte dar. Er sollte nicht zu groß eingestellt werden, da er sonst die Leistung beeinträchtigt: { func: function() { return !! E.alarmVisible; }}//Gibt die anzuzeigende Bildgruppe an }); ht.DoorWindow();//Schranktür door.setWidth(s3[0]);//Legen Sie die Länge des Grafikelements in der x-Achsenrichtung in der 3D-Topologie fest door.setHeight(1);//Legen Sie die fest Grafikelement in der 3D-Topologie Z-Achse in Länge door.setTall(s3[1]);//Steuern Sie die Länge des Knotengrundelements auf der y-Achse door.setElevation(0);//Legen Sie die Y-Koordinate der Mitte des Grundelements im 3D-Koordinatensystem door fest .setY(s3[2 ] * 0,5);//Stellen Sie die Position des Knotens auf der y-Achse ein door.setHost(node);//Stellen Sie die Adsorption ein door.s({//Legen Sie den Knotenstil fest setStyle 'all.color': color,/ /Legen Sie die Farbe der sechs Seiten des Knotens 'front.image' fest: doorFrontImg, //Legen Sie das vordere Bild des Knotens 'front.transparent' fest: true, //Legen Sie fest, ob die Vorderseite des Knotens transparent ist 'back .image': doorBackImg, //Setze das Bild auf die Rückseite des Knotens 'back.uv': [1,0, 1,1, 0,1, 0,0],// Passen Sie die UV-Karte hinter dem Knoten an. Wenn sie leer ist, ist der Standardwert [0,0, 0,1, 1,1, 1 ,0] ' dw.axis': 'right'//Legen Sie die Rotationsachse für die Erweiterungs- und Schließvorgänge des DoorWindow-Elements fest. Die möglichen Werte sind left|right|top|bottom|v|h }); var serverList = this ._serverList = []; var max = 6, list = E.randomList(max, Math.floor(Math.random() * (max - 2)) + 2); //Funktion zum Erhalten von Zufallszahlen, die in global.js var server, h = s3 deklariert sind [0] / 4; list.forEach(function(r) { var server = new E.Server({ //Server-Komponentenfarbe: 'rgb(51,49,49)', frontImg: 'Serverkomponente in Ordnung' }); server.s3(s3[0] - 2, h, s3[2] - 4);//Legen Sie die Knotengröße fest server.setElevation((r - max * 0.5) * (h + 2 ));//Stellen Sie die Koordinaten des Knotenmittelpunkts auf der y-Achse ein server.setHost(node);//Stellen Sie die Adsorption des Knotens ein serverList.push(server);//Zu serverList Serverknoten hinzufügen in });};
Das einzige, was im obigen Code nicht erwähnt wird, ist die Funktion Editor.randomList. Diese Funktion ist in der Datei global.js deklariert und wie folgt deklariert:
var E = window.Editor = { leftWidth: 0, topHeight: 40, randomList: function(max, size) { var list = [], ran; while (list.length < size) { ran = Math.floor(Math. random() * max); if (list.indexOf(ran) >= 0) continue; list.push(ran);
Okay, jetzt, da die Klassen für jeden Teil der Szene erstellt wurden, sollten wir die Szene erstellen und dann diese Grundelemente darin anhäufen!
SzenenerstellungSchüler, die damit vertraut sind, sollten wissen, dass für die Verwendung von HT zum Erstellen einer 3D-Szene lediglich eine neue 3D-Komponente erforderlich ist und die Szene dann über die Funktion addToDOM zum Körper hinzugefügt werden kann:
var g3d = E.main = new ht.graph3d.Graph3dView(); //3D-Szene
Die Datei main.js übernimmt hauptsächlich einige notwendige Elemente in der 3D-Szene, wie Wände, Böden, Türen, Klimaanlagen sowie die Erzeugungs- und Entladungspositionen aller Schränke sowie sehr wichtige interaktive Teile.
Ich werde den Code für die Erstellung von Wänden, Böden, Türen, Klimaanlagen und Schränken nicht veröffentlichen. Wenn Sie interessiert sind, überprüfen Sie bitte den Code selbst. Hier geht es hauptsächlich um das Doppelklicken auf den Schrank und alle mit dem Schrank verbundenen Objekte. Schranktüren, Serverausrüstung), um 3D zu erstellen. Die Mitte der Sichtlinie der Kamera bewegt sich zu einer bestimmten Position vor dem doppelt angeklickten Schrank, und diese Bewegung war vorher nicht gut, also dachte ich Ich habe mich lange mit diesem Teil befasst und schließlich auf die Implementierungsmethode dieser Demo verwiesen.
Um Auge und Mitte wiederholt festlegen zu können, wird der dem Festlegen dieser beiden Parameter entsprechende Inhalt in die Methoden setEye und setCenter gekapselt. Die Methode setCenter ähnelt der Methode setEye und wird hier nicht wiederholt:
//Legen Sie die Augenposition fest var setEye = function(eye, finish) { if (!eye) return; var e = g3d.getEye().slice(0),//Erhalten Sie den aktuellen Augenwert dx = eye[0] - e[0], dy = eye[1] - e[1], dz = eye[2] - e[2] // Einen 500-Millisekunden-Animationsübergang starten ht.Default.startAnim({ Dauer: 500, Easing: Easing,//Animationsbeschleunigungsfunktion FinishFunc: Finish ||. function() {}, //Funktion wird aufgerufen, nachdem die Animation endet Aktion: Funktion(v, t) {//Animation v so einstellen, dass die vorübergehende Beschleunigung dargestellt wird (t) Der Wert nach der Funktionsoperation, t stellt den Fortschritt der aktuellen Animation dar [0~1], allgemeine Attributänderungen basieren auf dem v-Parameter g3d.setEye([ //Setzen Sie das Auge in der 3D-Szene Der Wert des Auges ist ein Array, das den Werten der x-, y- und z-Achse entspricht: e[0] + dx * v, e[1] + dy * v, e[2] + dz * v ]); } }) ;};
Die Tatsache, dass ich die setCenter-Funktion nicht wiederholt deklariert habe, bedeutet nicht, dass diese Funktion nicht wichtig ist. Im Gegenteil, diese Funktion spielt eine entscheidende Rolle bei der Verschiebung der Sichtlinie um vor meiner Zielposition zu gehen (zumindest definiere ich sie für diesen Zweck), während sCenter Die Definition besteht darin, meinen Blick auf die Position des Ziels zu richten (zum Beispiel kann ich an meiner aktuellen Position stehen und auf das Objekt rechts hinter mir schauen, oder ich kann nach hinten rechts gehen und davor stehen). Es ist sehr wichtig, es zu genießen.
Das Doppelklick-Ereignis ist einfach. Hören Sie sich einfach das von HT gekapselte Ereignis an, bestimmen Sie den Ereignistyp und ergreifen Sie entsprechende Maßnahmen:
g3d.mi(function(e) {//addInteractorListener Ereignisüberwachungsfunktion if (e.kind !== 'doubleClickData') //Bestimmen Sie den Ereignistyp als Doppelklick-Knotenrückgabe; var data = e.data, p3 ; if (data. a('cabinet')) //Body p3 = data.p3(); else { host = data.getHost( //Das Adsorptionsobjekt des angeklickten Knotens abrufen if (host && host.a('cabinet')) {//Wenn das Adsorptionsobjekt Schrank ist p3 = host.p3(); } } if (!p3) return; //Setze die Bewegungsposition des mittleren Ziels auf The Position des Schranks setEye([p3[0], 211, p3[2] + 247] //Legen Sie die Position fest, an die sich das Auge bewegen soll});obere Navigationsleiste
Als ich dieses Beispiel zum ersten Mal sah, dachte ich, diese Person ist so großartig. Ich benutze HT schon so lange, aber ich konnte mit der ht.widget.Toolbar von HT immer noch keine so schönen Effekte erzielen Dabei wurde mir klar, dass dies tatsächlich mit HT gemacht wurde. Es ist erstaunlich, ich bin so dumm.
var form = E.top = new ht.widget.FormPane(); //Obere Formularkomponente form.setRowHeight(E.topHeight);//Setzen Sie die Zeilenhöhe form.setVGap(-E.topHeight);//Setzen Sie den horizontalen Abstand der Formularkomponente auf einen negativen Wert der beizubehaltenden Zeilenhöhe mehrere Zeilen an derselben Position Zeile form.setVPadding(0);//Legen Sie den oberen Rand des Formulars und den Abstand zwischen dem oberen Rand und dem Komponenteninhalt fest form.addRow([null, {//Fügen Sie dem Formular eine Reihe von Komponenten hinzu. Der erste Parameter ist ein Array von Elementen. Die Elemente können Zeichenfolgen, im JSON-Format beschriebene Komponentenparameterinformationen, HTML-Elemente oder Nullbilder sein: { icon: './symbols/ inputBG.json ', stretch: 'centerUniform' }}], [40, 260]);//Der zweite Parameter ist ein Array mit Breiteninformationen für jedes Element. Ein Breitenwert größer als 1 stellt einen festen absoluten Wert dar, und ein Breitenwert kleiner oder gleich 1 stellt einen relativen Wert dar eine Kombination aus 80+0,3 form.addRow([null, null , { id: 'searchInput', textField: {}}, { element: 'Visuelles Verwaltungssystem für Computerräume', Farbe: 'weiß', Schriftart: '18px arial , serifenlos'}, null, { button: { // label: 'ViewChange', icon: './symbols/viewChange.json', background: null, selectBackground: 'rgb(128,128,128)', borderColor: 'rgba(0, 0, 0, 0 ) ', onClicked: function() { E.focusTo(); } }}, null, { button: { // label: 'Alert', icon: './symbols/alarm.json', umschaltbar: wahr, ausgewählt: falsch, Hintergrund: null, selectBackground: 'rgb(128,128,128)', borderColor: 'rgba(0, 0, 0, 0)', onClicked: function( e) { E.setAlarmVisible(this.isSelected()); } }}, null], [40, 42, 218, 300, 0,1, 50, 10, 50, 10]);
Das Obige ist nur möglich, wird aber nicht wirklich zum HTML-Tag hinzugefügt, was bedeutet, dass jetzt nichts auf der Schnittstelle vorhanden ist! Vergessen Sie nicht, die 3D-Szene zum Textkörper hinzuzufügen, wenn die Seite geladen wird, und vergessen Sie nicht, das Formular zum Textkörper hinzuzufügen. Beim Festlegen des Fenstergrößenänderungsereignisses muss das Formular auch in Echtzeit aktualisiert werden:
window.addEventListener('load', function() { g3d.addToDOM(); //Fügen Sie die 3D-Szene zum Körper hinzu document.body.appendChild(E.top.getView()); //Fügen Sie das zugrunde liegende Div des hinzu Formularkomponente Zum Text hinzufügen window.addEventListener('resize', function() {//Auf Fenstergrößenänderungsereignisse warten E.top.iv();//Aktualisieren Sie das zugrunde liegende div des Formulars });});
Hier finden Sie eine Erklärung der Funktion addToDOM, die für das Verständnis des HT-Mechanismus sehr wichtig ist. HT-Komponenten sind im Allgemeinen in Container wie BorderPane, SplitView und TabView eingebettet. Die äußerste HT-Komponente erfordert, dass der Benutzer das von getView() zurückgegebene zugrunde liegende div-Element manuell zum DOM-Element der Seite hinzufügt Wenn sich die Größe des übergeordneten Containers ändert und es sich bei dem übergeordneten Container um vordefinierte Containerkomponenten von HT wie BorderPane und SplitView handelt, ruft der HT-Container automatisch rekursiv die Invalidierungsfunktion der untergeordneten Komponente auf, um die Aktualisierung zu benachrichtigen. Wenn es sich bei dem übergeordneten Container jedoch um ein natives HTML-Element handelt, kann die HT-Komponente nicht wissen, dass sie aktualisiert werden muss. Daher muss die äußerste HT-Komponente im Allgemeinen auf das Fenstergrößenänderungsereignis des Fensters hören und die Invalidierungsfunktion der äußersten aufrufen Komponente, die aktualisiert werden soll.
Um das Laden der äußersten Komponente zum Füllen des Fensters zu erleichtern, verfügen alle Komponenten von HT über die Funktion addToDOM. Die Implementierungslogik lautet wie folgt, wobei iv die Abkürzung für invalidate ist:
addToDOM = function(){ var self = this, view = self.getView(), style = view.style; document.body.appendChild(view); //Füge das zugrunde liegende Div der Szene hinzu style.left = ' 0';//HT setzt die Position des zugrunde liegenden Div aller Komponenten auf absolut style.right = '0'; style.top = '0'; window.addEventListener('resize', function () { self.iv(); }, false); //Ereignisse auf Fenstergrößenänderungen abhören und Komponentenänderungen und -aktualisierungen benachrichtigen}
Auf diese Weise ist der gesamte Code fertig. Sie können ihn mit der rechten Maustaste überprüfen und die entsprechende JSON-Datei aus dem Netzwerk abrufen.
Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, dass er für das Studium aller hilfreich ist. Ich hoffe auch, dass jeder das VeVb Wulin Network unterstützt.