WebGL Essentials deel III

Welkom terug bij dit derde en laatste deel in onze WebGL Essentials miniserie. In deze les bekijken we verlichting en voegen we 2D-objecten toe aan je scène. Er is veel nieuwe informatie hier, dus laten we direct naar binnen duiken!


Licht

Verlichting kan het meest technische en moeilijkste aspect van een 3D-toepassing zijn om te begrijpen. Een goed begrip van de verlichting is absoluut noodzakelijk.

Hoe werkt licht??

Voordat we ingaan op de verschillende soorten licht- en codetechnieken, is het belangrijk om te weten hoe licht werkt in de echte wereld. Elke lichtbron (bijv. Een gloeilamp, de zon, enz.) Genereert deeltjes die fotonen worden genoemd. Deze fotonen kaatsen rond objecten totdat ze uiteindelijk in onze ogen komen. Onze ogen zetten de fotonen om in een visueel "beeld". Dit is hoe we het zien. Licht is ook additief, wat betekent dat een object met meer kleur helderder is dan een object zonder kleur (zwart). Zwart is de volledige afwezigheid van kleur, terwijl wit alle kleuren bevat. Dit is een belangrijk onderscheid bij het werken met zeer heldere of "oververzadigde" lichten.

Helderheid is slechts één principe dat meerdere toestanden heeft. Reflectie kan bijvoorbeeld verschillende niveaus hebben. Een object, zoals een spiegel, kan volledig reflecterend zijn, terwijl andere objecten een mat oppervlak kunnen hebben. Transparantie bepaalt hoe objecten het licht buigen en breking veroorzaken; één object kan volledig transparant zijn terwijl anderen object ondoorzichtig kunnen zijn (of elke fase daartussen).

De lijst gaat verder, maar ik denk dat je al kunt zien dat licht niet eenvoudig is.

Als je zelfs een kleine scène wilde om echt licht te simuleren, zou het draaien op ongeveer 4 frames per uur, en dat is op een krachtige computer. Om dit probleem te omzeilen, gebruiken programmeurs trucs en technieken om semi-realistische belichting te simuleren met een redelijke framesnelheid. Je moet een compromis bedenken tussen realisme en snelheid. Laten we een paar van deze technieken eens bekijken.

Voordat ik begin met het uitwerken van verschillende technieken, zou ik u een kleine disclaimer willen geven. Er is veel controverse over de exacte namen voor de verschillende verlichtingstechnieken, en verschillende mensen zullen je verschillende uitleg geven over wat "Ray Casting" of "Light Mapping" is. Dus voordat ik de haatmail krijg, zou ik willen zeggen dat ik de namen ga gebruiken die ik heb geleerd; sommige mensen zijn het misschien niet eens over mijn exacte titels. In ieder geval is het belangrijk om te weten wat de verschillende technieken zijn. Dus zonder verder oponthoud, laten we aan de slag gaan.

Je moet een compromis bedenken tussen realisme en snelheid.

Ray Tracing

Ray Tracing is een van de meer realistische verlichtingstechnieken, maar het is ook een van de duurdere. Ray Tracing emuleert echt licht; het zendt "fotonen" of "stralen" uit de lichtbron en stuitert ze rond. In de meeste ray tracing-implementaties komen de stralen van de "camera" en stuiteren op de scène in de tegenovergestelde richting. Deze techniek wordt meestal gebruikt in films of scènes die van tevoren kunnen worden weergegeven. Dit wil niet zeggen dat je ray tracing niet kunt gebruiken in een real-time applicatie, maar dit dwingt je om andere dingen in de scene te verminderen. U moet bijvoorbeeld mogelijk het aantal "bounces" verminderen dat de stralen moeten uitvoeren, of u kunt ervoor zorgen dat er geen objecten zijn met reflecterende of brekende oppervlakken. Ray Tracing kan ook een haalbare optie zijn als uw toepassing maar heel weinig licht en objecten heeft.

Als u een real-time toepassing hebt, kunt u mogelijk delen van uw scène precompileren.

Als de lampjes in uw toepassing niet bewegen of slechts in een klein gebied tegelijk bewegen, kunt u de verlichting precompileren met een zeer geavanceerd stralingsalgoritme en een klein gebied rond de bewegende lichtbron opnieuw berekenen. Als je bijvoorbeeld een spel maakt waarbij de lichten niet bewegen, kun je de wereld precompileren met alle gewenste lichten en effecten. Dan kun je gewoon een schaduw rond je karakter toevoegen wanneer hij beweegt. Dit produceert een zeer hoogwaardige uitstraling met een minimale hoeveelheid verwerking.

Ray Casting

Straalgieten lijkt sterk op ray tracing, maar de "fotonen" stuiteren niet van objecten of hebben geen interactie met verschillende materialen. In een typische toepassing zou je in principe beginnen met een donkere scène en dan zou je lijnen van de lichtbron tekenen. Alles wat het licht raakt, is verlicht; al het andere blijft donker. Deze techniek is aanzienlijk sneller dan ray tracing en geeft nog steeds een realistisch schaduweffect. Maar het probleem met ray-casting is de beperkendheid ervan; je hebt niet veel ruimte om mee te werken bij het proberen om effecten zoals reflecties toe te voegen. Meestal moet je een soort compromis bedenken tussen ray-casting en ray tracing, balancerend tussen snelheid en visuele effecten.

Het grootste probleem met deze beide technieken is dat WebGL u geen toegang geeft tot enige hoekpunten, behalve de actieve.

Dit betekent dat je alles op de CPU moet uitvoeren (zoals op de grafische kaart), of dat je een tweede arcering hebt gemaakt die alle belichting berekent en de informatie opslaat in een nepstructuur. U moet dan de textuurgegevens weer in de lichtinformatie decomprimeren en deze toewijzen aan de hoekpunten. Dus eigenlijk is de huidige versie van WebGL hier niet erg geschikt voor. Ik zeg niet dat het niet kan, ik zeg alleen dat WebGL je niet zal helpen.

Schaduwtoewijzing

Ray Tracing kan ook een haalbare optie zijn als uw toepassing maar heel weinig licht en objecten heeft.

Een veel beter alternatief voor ray-casting in WebGL is shadow mapping. Het geeft hetzelfde effect als ray-casting, maar het gebruikt een andere benadering. Schaduw-mapping lost niet al je problemen op, maar WebGL is er semi-geoptimaliseerd voor. Je kunt het zien als een soort hack, maar shadow mapping wordt gebruikt in echte pc- en consoletoepassingen.

Dus wat vraag je je af?

U moet begrijpen hoe WebGL zijn scènes weergeeft om deze vraag te beantwoorden. WebGL duwt alle hoekpunten in de hoekpuntshader, die de uiteindelijke coördinaten berekent voor elke vertex nadat de transformaties zijn toegepast. Om vervolgens tijd te besparen, verwijdert WebGL de hoekpunten die achter andere objecten zijn verborgen en tekent alleen de essentiële objecten. Als je je herinnert hoe stralen werkt, werpt het lichtstralen op de zichtbare objecten. Dus stellen we de "camera" van onze scène in op de coördinaten van de lichtbron en wijzen deze in de richting waarin we het licht willen zien staan. Vervolgens verwijdert WebGL automatisch alle hoekpunten die niet zichtbaar zijn voor het licht. We kunnen deze gegevens vervolgens opslaan en gebruiken wanneer we de scène laten weten welke van de hoekpunten worden verlicht.

Deze techniek klinkt goed op papier maar heeft enkele nadelen:

  • WebGL staat u niet toe toegang te hebben tot de dieptebuffer; je moet creatief zijn in de fragment-shader wanneer je probeert deze gegevens op te slaan.
  • Zelfs als u alle gegevens opslaat, moet u deze nog steeds toewijzen aan de hoekpunten voordat ze de vertex-array binnengaan wanneer u uw scène rendert. Dit vereist extra CPU-tijd.

Al deze technieken vereisen een behoorlijke hoeveelheid sleutelen aan WebGL. Maar ik zal je een heel basale techniek laten zien voor het produceren van een diffuus licht om je objecten een beetje persoonlijkheid te geven. Ik zou het geen realistisch licht noemen, maar het geeft je objectdefinitie. Deze techniek gebruikt de normalenmatrix van het object om de hoek van het licht te berekenen in vergelijking met het oppervlak van het object. Het is snel, efficiënt en vereist geen hacking met WebGL. Laten we beginnen.


Licht toevoegen

Laten we beginnen met het bijwerken van de shaders om verlichting te integreren. We moeten een booleaanse waarde toevoegen die bepaalt of het object moet worden verlicht. Vervolgens hebben we de actuele normalen vertex nodig en transformeren deze zodanig dat deze overeenkomt met het model. Ten slotte moeten we een variabele maken om het uiteindelijke resultaat door te geven aan de fragmentshader. Dit is de nieuwe vertex-arcering:

Als we geen licht gebruiken, geven we alleen een leeg hoekpunt door aan de fragmentshader en blijft de kleur hetzelfde. Wanneer lichten worden ingeschakeld, berekenen we de hoek tussen de richting van het licht en het oppervlak van het object met de puntfunctie op de normaal, en vermenigvuldigen we het resultaat met de kleur van het licht als een soort masker om op het object te leggen.

Foto van oppervlaknormalen door Oleg Alexandrov.

Dit werkt omdat de normalen al loodrecht op het oppervlak van het object staan ​​en de puntfunctie geeft ons een getal op basis van de hoek van het licht tot het normale. Als normaal en licht bijna parallel zijn, retourneert de puntfunctie een positief getal, wat betekent dat het licht naar het oppervlak is gericht. Wanneer normaal en licht loodrecht zijn, is het oppervlak evenwijdig aan het licht en retourneert de functie nul. Alles dat hoger is dan 90 graden tussen het licht en de normale resultaten resulteert in een negatief getal, maar we filteren dit met de functie "max nul".

Laat me je nu de fragmentshader tonen:

Deze shader is vrijwel hetzelfde uit eerdere delen van de serie. Het enige verschil is dat we de kleur van de textuur vermenigvuldigen met het lichtniveau. Hierdoor worden verschillende delen van het object helderder of donkerder en krijgt het wat diepte.

Dat is alles voor de shaders, laten we nu naar de WebGL.js bestand en wijzig onze twee klassen.

Ons Framework bijwerken

Laten we beginnen met de GLObject klasse. We moeten een variabele toevoegen voor de normalenreeks. Hier is wat het bovenste deel van uw GLObject zou er nu moeten uitzien als:

functie GLObject (VertexArr, TriangleArr, TextureArr, ImageSrc, NormalsArr) this.Pos = X: 0, Y: 0, Z: 0; this.Scale = X: 1.0, Y: 1.0, Z: 1.0; this.Rotation = X: 0, Y: 0, Z: 0; this.Vertices = VertexArr; // Array om de normale gegevens te behouden this.Normals = NormalsArr; // De rest van GLObject gaat hier verder

Deze code is redelijk rechttoe rechtaan. Laten we nu teruggaan naar het HTML-bestand en de array Normals aan ons object toevoegen.

In de Klaar() functie waar we ons 3D-model laden, moeten we de parameter voor de normalenreeks toevoegen. Een lege array betekent dat het model geen normale gegevens bevat en dat we het object zonder licht moeten tekenen. In het geval dat de normalenreeks gegevens bevat, zullen we deze gewoon doorgeven aan de GLObject voorwerp.

We moeten ook het WebGL klasse. We moeten variabelen koppelen aan de shaders direct nadat we de shaders laden. Laten we de normalen vertex toevoegen; je code zou er nu als volgt uit moeten zien:

// Link Vertex Positie Attribuut van Shader this.VertexPosition = this.GL.getAttribLocation (this.ShaderProgram, "VertexPosition"); this.GL.enableVertexAttribArray (this.VertexPosition); // Link Textuur Coordinate Attribuut van Shader this.VertexTexture = this.GL.getAttribLocation (this.ShaderProgram, "TextureCoord"); this.GL.enableVertexAttribArray (this.VertexTexture); // Dit is het nieuwe attributen attribuut Normen this.VertexNormal = this.GL.getAttribLocation (this.ShaderProgram, "VertexNormal"); this.GL.enableVertexAttribArray (this.VertexNormal);

Laten we het volgende bijwerken PrepareModel () functie en voeg een code toe om de normgegevens te bufferen wanneer deze beschikbaar is. Voeg de nieuwe code toe vlak voor de Model.Ready verklaring onderaan:

if (false! == Model.Normals) Buffer = this.GL.createBuffer (); this.GL.bindBuffer (this.GL.ARRAY_BUFFER, Buffer); this.GL.bufferData (this.GL.ARRAY_BUFFER, nieuwe Float32Array (Model.Normals), this.GL.STATIC_DRAW); Model.Normals = Buffer;  Model.Ready = true;

Last but not least, werk de actualiteit bij Trek functie om al deze veranderingen op te nemen. Er is een paar veranderingen hier dus wees geduldig. Ik ga stukje bij beetje door de hele functie heen:

this.Draw = function (Model) if (Model.Image.ReadyState == true && Model.Ready == false) this.PrepareModel (Model);  if (Model.Ready) this.GL.bindBuffer (this.GL.ARRAY_BUFFER, Model.Vertices); this.GL.vertexAttribPointer (this.VertexPosition, 3, this.GL.FLOAT, false, 0, 0); this.GL.bindBuffer (this.GL.ARRAY_BUFFER, Model.TextureMap); this.GL.vertexAttribPointer (this.VertexTexture, 2, this.GL.FLOAT, false, 0, 0);

Tot hier is hetzelfde als voorheen. Nu komt het normale deel:

 // Check For Normals if (false! == Model.Normals) // Connect The normalals buffer to the Shader this.GL.bindBuffer (this.GL.ARRAY_BUFFER, Model.Normals); this.GL.vertexAttribPointer (this.VertexNormal, 3, this.GL.FLOAT, false, 0, 0); // Vertel de arcering om verlichting var te gebruiken UseLights = this.GL.getUniformLocation (this.ShaderProgram, "UseLights"); this.GL.uniform1i (UseLights, true);  else // Zelfs als ons object geen normgegevens heeft, moeten we nog steeds iets doorgeven // Dus geef ik in plaats hiervan de Vertices.GL.bindBuffer (this.GL.ARRAY_BUFFER, Model.Vertices); this.GL.vertexAttribPointer (this.VertexNormal, 3, this.GL.FLOAT, false, 0, 0); // Vertel de arcering om verlichting var te gebruiken UseLights = this.GL.getUniformLocation (this.ShaderProgram, "UseLights"); this.GL.uniform1i (UseLights, false); 

We controleren om te zien of het model normale gegevens heeft. Als dat zo is, wordt de buffer verbonden en wordt de boolean ingesteld. Als dit niet het geval is, heeft de arcering nog steeds een soort gegevens nodig of krijgt u een foutmelding. Dus in plaats daarvan heb ik de hoekpuntenbuffer gepasseerd en de UseLight boolean to vals. Je kunt dit omzeilen door meerdere shaders te gebruiken, maar ik dacht dat dit eenvoudiger zou zijn voor wat we proberen te doen.

 this.GL.bindBuffer (this.GL.ELEMENT_ARRAY_BUFFER, Model.Triangles); // Genereer de Perspectiefmatrix var PerspectiveMatrix = MakePerspective (45, this.AspectRatio, 1, 1000.0); var TransformMatrix = Model.GetTransforms ();

Ook dit deel van de functie is nog steeds hetzelfde.

 var NormalsMatrix = MatrixTransponeren (InverseMatrix (TransformMatrix));

Hier berekenen we de normalen-transformatiematrix. Ik zal het bespreken MatrixTranspose () en InverseMatrix () functies in een minuut. Als u de transformatiematrix voor de matrix Normalen wilt berekenen, moet u de inverse matrix van de reguliere transformatiematrix van het object transponeren. Hierover later meer.

 // Stel slot 0 in als de actieve structuur this.GL.activeTexture (this.GL.TEXTURE0); // Laad in de textuur in het geheugen this.GL.bindTexture (this.GL.TEXTURE_2D, Model.Image); // Update The Texture Sampler in de fragmentshader om slot 0 this.GL.uniform1i (this.GL.getUniformClassificatie (this.ShaderProgram, "uSampler"), 0) te gebruiken; // Stel de perspectieven en transformatiematrices var pmatrix = this.GL.getUniformClassificatie (this.ShaderProgram, "PerspectiveMatrix"); this.GL.uniformMatrix4fv (pmatrix, false, nieuwe Float32Array (PerspectiveMatrix)); var tmatrix = this.GL.getUniformClassificatie (this.ShaderProgram, "TransformationMatrix"); this.GL.uniformMatrix4fv (tmatrix, false, nieuwe Float32Array (TransformMatrix)); var nmatrix = this.GL.getUniformClassificatie (this.ShaderProgram, "NormalTransformation"); this.GL.uniformMatrix4fv (nmatrix, false, nieuwe Float32Array (NormalsMatrix)); // Teken de driehoeken this.GL.drawElements (this.GL.TRIANGLES, Model.TriangleCount, this.GL.UNSIGNED_SHORT, 0); ;

U kunt eenvoudig de bron van een WebGL-toepassing bekijken voor meer informatie.

Dit is de rest van de Trek() functie. Het is bijna hetzelfde als voorheen, maar er is de toegevoegde code die de normalen-matrix verbindt met de shaders. Laten we nu teruggaan naar die twee functies die ik heb gebruikt om de normalen-transformatiematrix te krijgen.

De InverseMatrix () functie accepteert een matrix en retourneert de inverse matrix. Een inverse matrix is ​​een matrix die, vermenigvuldigd met de oorspronkelijke matrix, een identiteitsmatrix retourneert. Laten we naar een eenvoudig algebra-voorbeeld kijken om dit te verduidelijken. De inverse van het getal 4 is 1/4, omdat wanneer 1/4 x 4 = 1. Het "één" equivalent in matrices is een identiteitsmatrix. Daarom, de InverseMatrix () functie retourneert de identiteitsmatrix voor het argument. Hier is deze functie:

 functie InverseMatrix (A) var s0 = A [0] * A [5] - A [4] * A [1]; var s1 = A [0] * A [6] - A [4] * A [2]; var s2 = A [0] * A [7] - A [4] * A [3]; var s3 = A [1] * A [6] - A [5] * A [2]; var s4 = A [1] * A [7] - A [5] * A [3]; var s5 = A [2] * A [7] - A [6] * A [3]; var c5 = A [10] * A [15] - A [14] * A [11]; var c4 = A [9] * A [15] - A [13] * A [11]; var c3 = A [9] * A [14] - A [13] * A [10]; var c2 = A [8] * A [15] - A [12] * A [11]; var c1 = A [8] * A [14] - A [12] * A [10]; var c0 = A [8] * A [13] - A [12] * A [9]; var invdet = 1.0 / (s0 * c5 - s1 * c4 + s2 * c3 + s3 * c2 - s4 * c1 + s5 * c0); var B = []; B [0] = (A [5] * c5 - A [6] * c4 + A [7] * c3) * invdet; B [1] = (-A [1] * c5 + A [2] * c4 - A [3] * c3) * invdet; B [2] = (A [13] * s5 - A [14] * s4 + A [15] * s3) * invdet; B [3] = (-A [9] * s5 + A [10] * s4 - A [11] * s3) * invdet; B [4] = (-A [4] * c5 + A [6] * c2 - A [7] * c1) * invdet; B [5] = (A [0] * c5 - A [2] * c2 + A [3] * c1) * invdet; B [6] = (-A [12] * s5 + A [14] * s2 - A [15] * s1) * invdet; B [7] = (A [8] * s5 - A [10] * s2 + A [11] * s1) * invdet; B [8] = (A [4] * c4 - A [5] * c2 + A [7] * c0) * invdet; B [9] = (-A [0] * c4 + A [1] * c2 - A [3] * c0) * invdet; B [10] = (A [12] * s4 - A [13] * s2 + A [15] * s0) * invdet; B [11] = (-A [8] * s4 + A [9] * s2 - A [11] * s0) * invdet; B [12] = (-A [4] * c3 + A [5] * c1 - A [6] * c0) * invdet; B [13] = (A [0] * c3 - A [1] * c1 + A [2] * c0) * invdet; B [14] = (-A [12] * s3 + A [13] * s1 - A [14] * s0) * invdet; B [15] = (A [8] * s3 - A [9] * s1 + A [10] * s0) * invdet; terugkeer B; 

Deze functie is behoorlijk gecompliceerd en om je de waarheid te zeggen, begrijp ik niet volledig waarom de wiskunde werkt. Maar ik heb de essentie hierboven al uitgelegd. Ik heb deze functie niet bedacht; het is in ActionScript geschreven door Robin Hilliard.

De volgende functie, MatrixTranspose (), is een stuk eenvoudiger te begrijpen. Het geeft de "getransponeerde" versie van zijn inputmatrix terug. Kortom, het draait gewoon de matrix op zijn kant. Hier is de code:

functie MatrixTransponering (A) retourneer [A [0], A [4], A [8], A [12], A [1], A [5], A [9], A [13], A [ 2], A [6], A [10], A [14], A [3], A [7], A [11], A [15]]; 

In plaats van in horizontale rijen te gaan (bijv. A [0], A [1], A [2] ...) daalt deze functie verticaal (A [0], A [4], A [8] ...).

Je bent goed om te gaan na het toevoegen van deze twee functies aan je WebGL.js bestand en elk model dat de normgegevens bevat, moet grijs zijn. Je kunt rond spelen met de richting en kleur van het licht in de vertexshader om verschillende effecten te krijgen.

Er is nog een laatste onderwerp dat ik wil behandelen, en dat is het toevoegen van 2D-inhoud aan onze scène. Het toevoegen van 2D-componenten op een 3D-scène kan vele voordelen hebben. Het kan bijvoorbeeld worden gebruikt om coördinaatinformatie weer te geven, een minikaart, instructies voor uw app en de lijst gaat aan. Dit proces is niet zo eenvoudig als je zou denken, dus laten we het eens bekijken.


2D V.S. 2.5D

Met HTML kunt u de WebGL-API en de 2D-API niet vanaf hetzelfde canvas gebruiken.

U denkt misschien: "Waarom niet alleen de ingebouwde HTML5 2D-API van het canvas gebruiken?" Welnu, het probleem is dat HTML je de WebGL API en de 2D API niet van hetzelfde canvas laat gebruiken. Nadat u de context van het canvas hebt toegewezen aan WebGL, kunt u deze niet gebruiken met de 2D-API. HTML5 komt eenvoudig terug nul wanneer je de 2D-context probeert te krijgen. Dus hoe kom je hier dan omheen? Wel, ik geef je twee opties.

2.5D

2.5D, voor degenen die zich niet bewust zijn, is wanneer je 2D-objecten (objecten zonder diepte) in een 3D-scène zet. Tekst toevoegen aan een scène is een voorbeeld van 2.5D. U kunt de tekst uit een afbeelding nemen en deze als een textuur toepassen op een 3D-vlak, of u kunt een 3D-model voor de tekst krijgen en deze op uw scherm weergeven.

De voordelen van deze aanpak zijn dat u niet twee doeken nodig heeft en dat het sneller zou zijn om te tekenen als u alleen eenvoudige vormen in uw toepassing gebruikte.

Maar om dingen als tekst te doen, moet je ofwel afbeeldingen hebben van alles wat je wilt schrijven, of een 3D-model voor elke letter (een beetje overdreven, naar mijn mening).

2D

Het alternatief is om een ​​tweede canvas te maken en over het 3D-canvas te leggen. Ik geef de voorkeur aan deze aanpak omdat het beter uitgerust lijkt om 2D-inhoud te tekenen. Ik ga niet beginnen met het maken van een nieuw 2D-raamwerk, maar laten we gewoon een eenvoudig voorbeeld maken waarin we de coördinaten van het model weergeven, samen met de huidige rotatie. Laten we een tweede canvas toevoegen aan het HTML-bestand direct achter het WebGL-canvas. Hier is het nieuwe canvas samen met de huidige:

  Uw browser ondersteunt het Canvas van HTML5 niet.   Uw browser ondersteunt het Canvas van HTML5 niet. 

Ik heb ook een aantal inline CSS toegevoegd om het tweede canvas bovenop de eerste te plaatsen. De volgende stap is om een ​​variabele voor het 2D-canvas te maken en de bijbehorende context te krijgen. Ik ga dit doen in de Klaar() functie. Uw bijgewerkte code zou er ongeveer zo uit moeten zien:

var GL; var gebouw; var Canvas2D; function Ready () // Gl Declaration and Load model function Here Canvas2D = document.getElementById ("2DCanvas"). getContext ("2d"); Canvas2D.fillStyle = "# 000"; 

Aan de bovenkant kunt u zien dat ik een globale variabele voor het 2D-canvas heb toegevoegd. Vervolgens heb ik twee regels toegevoegd aan de onderkant van de Klaar() functie. De eerste nieuwe regel krijgt de 2D-context en de tweede nieuwe regel stelt de kleur in op zwart.

De laatste stap is het tekenen van de tekst in de Bijwerken() functie:

function Update () Building.Rotation.Y + = 0.3 // Wis het canvas uit de vorige trekking Canvas2D.clearRect (0, 0, 600, 400); // Title Text Canvas2D.font = "25px sans-serif"; Canvas2D.fillText ("Building", 20, 30); // Eigenschappen van Object Canvas2D.font = "16px sans-serif"; Canvas2D.fillText ("X:" + Building.Pos.X, 20, 55); Canvas2D.fillText ("Y:" + Building.Pos.Y, 20, 75); Canvas2D.fillText ("Z:" + Building.Pos.Z, 20, 95); Canvas2D.fillText ("Rotation:" + Math.floor (Building.Rotation.Y), 20, 115); GL.GL.clear (16384 | 256); GL.Draw (Gebouw); 

We beginnen met het draaien van het model op zijn Y-as en vervolgens wissen we het 2D-canvas van alle eerdere inhoud. Vervolgens stellen we de lettergrootte in en tekenen we wat tekst voor elke as. De fillText () methode accepteert drie parameters: de te tekenen tekst, de x-coördinaat en de y-coördinaat.

De eenvoud spreekt voor zich. Dit kan een beetje overkill geweest zijn om wat eenvoudige tekst te tekenen; je had eenvoudig de tekst gewoon in een positie kunnen schrijven

of

element. Maar als je iets doet zoals het tekenen van vormen, sprites, een gezondheidsbalk, enz., Dan is dit waarschijnlijk je beste optie.


Laatste gedachten

In het kader van de laatste drie tutorials hebben we een mooie, zij het standaard, 3D-engine gemaakt. Ondanks zijn primitieve aard, geeft het je een solide basis om van te werken. Vooruit kijkend, stel ik voor om naar andere kaders als three.js of glge te kijken om een ​​idee te krijgen van wat mogelijk is. Bovendien wordt WebGL in de browser uitgevoerd en kunt u gemakkelijk de bron van een WebGL-toepassing bekijken voor meer informatie.

Ik hoop dat je deze instructiereeks leuk vond en laat zoals altijd je opmerkingen en vragen achter in het gedeelte 'Opmerkingen' hieronder.