WebGL Med Three.js Shaders

3D-grafik i webbläsaren har varit ett ämne av intresse sedan introduktionen. Men om du skulle skapa dina appar med vanlig gammal WebGL, skulle det ta åldrar. Nyligen har några riktigt användbara bibliotek blivit tillgängliga. Three.js är en av de mest populära, och i den här serien kommer jag att visa dig hur du gör det bästa för att skapa fantastiska 3D-upplevelser för dina användare.

Jag förväntar dig att du ska ha en grundläggande förståelse för 3D-rymden innan du börjar läsa den här handledningen eftersom jag inte kommer att förklara saker som koordinater, vektorer etc.


Ett ord om Shaders

Om du redan vet vad shaders är, kan du hoppa över det här steget. Shaders är i princip program skrivna i GLSL (Graphics Layer Scripting Language), som exekveras på GPU. Detta gör dem extremt användbara, eftersom vi kan ta lite arbete från CPU: n och lägga den på GPU för att öka prestanda. Det finns två typer: vertex och fragment shaders. Vertex shaders används för att modifiera objektets struktur (flytta kryssarna) och fragmentskärare gör ändringar i pixlarna som ritas.


Steg 1: Vertex Shader

Vi börjar med den enklare. Denna skuggning kommer att modifiera placeringen av vektorerna i nätet, vilket resulterar i rörliga ytor. Sätt in den här koden i av din app:

 

De typ Attributet på detta skript kommer inte att förstås av webbläsaren, så det kommer inte att bli utfört (vi kommer att skicka innehållet till Three.js-materialet senare). I de två första raderna definierar vi två variabler. Den första är likformig flyt tid. Uniformer överförs till både vertex och fragment shaders. Därefter varierar det vec2 vUv. Varianter är gränssnittet mellan vertex och fragmentskäraren. tid kommer att hålla tiden i millisekunder sedan appen startades, vilket vi kommer att använda för att beräkna nya positioner av vertexes. I VUV Vi lagrar UV-värdet (texturvektorn) för varje vertex, så vi kan använda det i fragmentskärmen.

Därefter finns det void main () deklaration. Alla shaders måste ha denna funktion. Här passerar vi UV-kanten i vertexet till vårt VUV och beräknar vertexens nya position. Slutligen ställer vi in gl_Position, som i själva verket sätter positionen på vertexen. Men också, vi måste multiplicera den beräknade positionen tidigare av projectionMatrix och modelViewMatrix, två matriser som Three.js levererar till oss. Detta är nödvändigt för att om vi inte gör det, kommer GPU inte att överväga den punkt som vi ser på vertexen. Låt oss nu flytta till fragmentskäraren.


Steg 2: Fragment Shader

Nu är det här stället där allt magi händer. Fragment shaders ansvarar för alla dessa snygga spel. Den vi ska använda är ganska enkel, så förvänta dig inte att se en scen från Crysis 3 efter att du har använt den. Sätt in följande kod under din vertex shader:

 

Som du kan se på toppen av skuggaren finns det våra två variabler igen. Du måste komma ihåg att alla variabler du använder (utom de från Three.js) måste definieras i varje skugga som de används i.

I void main () funktion, beräknar vi färgerna baserat på fragmentets tid och UV (fragmentskärmar fungerar på fragment, som består av vertikaler, så värdena på varierande variabler interpoleras i fragmentskärmen). Gnugga med dessa nummer och funktioner (kom bara ihåg att färgvärdena måste vara positiva).

Slutligen ställer vi in gl_FragColor variabel som sätter fragmentets färg.

Om du öppnar din webbläsare nu ändras ingenting, eftersom vi måste ändra objektets material så att det använder shaders.


Steg 3: THREE.ShaderMaterial

Det här specialmaterialet används när vi behöver använda shaders. Låt oss ändra materialet i objektet som vi bifogade till vår modell i den föregående delen av denna serie. Först definiera uniformer array som kommer att användas för att överföra variabler till shaders:

 var uniformer = tid: typ: "f", värde: 0, upplösning: typ: "v2", värde: nytt THREE.Vector2, textur: typ: "t", värde: THREE.ImageUtils. loadTexture ('./box.png');

Därefter i Loader.load definiera Artikels material och använd det:

 var itemMaterial = nytt THREE.ShaderMaterial (uniformer: uniformer, vertexShader: document.getElementById ('cubeVertexShader'). innerHTML, fragmentShader: document.getElementById ('cubeFragmentShader'). innerHTML); item = new THREE.Mesh (new THREE.CubeGeometry (100, 10, 10), itemMaterial);

Nu, om du öppnar webbläsaren, bör du se att den röda strålen ändrade sina färger:


Men färgerna förändras inte, och nätet är inte animerat heller. För att ändra det måste vi uppdatera tid variabel i shadersna varje gång en ram ritas. Gå till göra funktion och lägg till den här raden efter clock.getDelta () ring upp:

 uniforms.time.value + = delta * 10;

Nu om du öppnar webbläsaren ska du se ett snyggt animerat och färgstarkt objekt:



Ett ord om prestanda

Om vi ​​skulle skapa en sådan textur effekt genom att till exempel använda HTML5 Canvas, skulle processen ta för mycket av CPU: s cykler, vilket resulterar i lags. Men alla shaders exekveras på GPU, som är optimerad för alla operationer på grafik och är fokuserad endast på dem. Att skilja grafiska och icke-grafiska beräkningar är nyckeln till en bra app.

Om du vill skapa något riktigt med hjälp av WebGL, låt mig försäkra dig om att du måste flytta så mycket arbete som möjligt till GPU, för att göra din ansökan smidig och lyhörd.


Slutsats

Som du kan se, använder Three.js oss att skapa 3D-grafik i webbläsaren väldigt enkelt, och resultaten är faktiskt ganska bra. Men de kan bli ännu bättre, ta en titt på dessa exempel från Three.js hemsida:

  • Hyperlapse
  • TNT för två

Med tillräckligt med tid, ett kreativt sinne och Three.js kan du skapa fantastiska appar som de också. Jag kommer att vara mer än glad att se dina Three.js-skapelser. Tack för att du läser.