Animera Bilder och Videor med curtains.js

0
56

Medan du surfar på den senaste award-vinnande webbplatser, du kan märka en massa fina förvrängning animationer eller snygga 3D-effekter. De flesta av dem är skapade med WebGL, en API så att GPU-accelererade bildbehandling effekter och animationer. De tenderar också att använda bibliotek byggt på toppen av WebGL som three.js eller pixi.js. Båda är mycket kraftfulla verktyg för att skapa respektive 2D-och 3D-scener.

Men, du bör hålla i minnet att dessa bibliotek var inte ursprungligen avsedd att skapa bildspel eller animera DOM-element. Det är ett bibliotek som är avsedda just för att, om, och vi kommer att gå igenom hur man använder det här i detta inlägg.

WebGL, CSS Positionering och Lyhördhet

Säg att du arbetar med ett bibliotek som three.js eller pixi.js och du vill använda den för att skapa interaktioner, som mouseover och bläddra händelser på element. Kanske du stöter på problem! Hur skulle du placera din WebGL element i förhållande till de dokument och andra DOM-element? Hur skulle hantera lyhördhet?

Detta är exakt vad jag hade i åtanke när du skapar curtains.js.

Curatins.js gör att du kan skapa en plan som innehåller bilder och videor (i WebGL vi kommer att kalla dem texturer) som fungerar som vanlig HTML-element, placering och storlek definieras av CSS-regler. Men dessa plan kan förbättras med oändliga möjligheter för WebGL och shaders.

Vänta, shaders?

Shaders är små program skrivna i GLSL som kommer att berätta för din GPU-hur till göra din plan. Att veta hur shaders arbete är obligatoriskt här eftersom detta är hur vi kommer att hantera animationer. Om du aldrig har hört talas om dem, kanske du vill lära dig grunderna först. Det finns gott om bra webbplatser för att lära dig dem, som Boken av Shaders.

Nu när du får idén, låt oss skapa vår första plan!

Installation av ett grundläggande plan

För att visa vår första plan, vi kommer att behöva lite om HTML, CSS och JavaScript för att skapa planet. Då vår shaders kommer att animera den.

HTML –

HTML-kommer att bli riktigt enkelt så här. Vi kommer att skapa en <div> som kommer att hålla vår duk, och en div som kommer att hålla vår bild.

<body>
<!– div som kommer att hålla våra WebGL duk –>
<div id=”duk”></div>

<!– div används för att skapa vår planet –>
<div class=”plane”>

<!– bild som kommer att användas som en struktur av vår planet –>
<img src=”path/to/my-image.jpg” />

</div>

</body>
CSS

Vi kommer att använda CSS för att se till <div> som omsluter duken kommer att vara större än vår planet, och tillämpa valfri storlek till planet div. (Vår WebGL plan kommer att ha exakt samma storlek och positioner i denna div.)

body {
/* gör kroppen in i vårt virtuella */
position: relative;
width: 100%;
höjd: 100vh;
margin: 0;

/* dölj rullningslister */
overflow: hidden;
}

#duk {
/* se till att arbetsytan omslag passar dokumentet */
position: absolute;
top: 0;
rätt: 0;
bottom: 0;
left: 0;
}
.plan {
/* definiera storleken på din plan */
bredd: 80%;
max bredd: 1400px;
höjd: 80vh;
position: relative;
topp: 10vh;
marginal: 0 auto;
}

.planet img {
/* dölja img-element. * /
display: none;
}
JavaScript

Det är lite mer arbete i JavaScript. Vi måste initiera våra WebGL sammanhang, skapa en planet med enhetliga parametrar och använda det.

fönster.onload = function() {
// klara-id för den div som kommer att avsluta canvas att sätta upp våra WebGL sammanhang och lägg duken på våra omslag
var webGLCurtain = nya Gardiner(“bakgrund”);

// hämta vår planet element
var planeElement = dokument.getElementsByClassName(“plan”)[0];

// set våra ursprungliga parametrarna (grundläggande uniformer)
var params = {
vertexShaderID: “plan-vs”, // vertex shader-ID
fragmentShaderID: “plan-fs”, // våra framgent shader-ID
uniformer: {
tid: {
namn: “uTime”, // enhetliga namn som kommer att skickas till våra shaders
typ: “1f”, // detta innebär att vår uniform är en float
värde: 0,
},
}
}

// skapa vår planet mesh
var plan = webGLCurtain.addPlane(planeElement, params);

// använd onRender metod för vår planet sköt på varje requestAnimationFrame samtal
– planet.onRender(function() {
– planet.uniformer.tid.värde++; // uppdatera vår tid enhetligt värde
});

}
Shaders

Vi behöver skriva vertex shader. Det kommer inte att göra så mycket, förutom position vårt plan baseras på den modell som visa och projektion matris och passera varyings till fragment shader:

<!– vertex shader –>
<script id=”plane-vs” typ=”x-shader/x-vertex”>
#ifdef GL_ES
precision mediump float;
#endif

// dessa är de obligatoriska attribut som sätter lib
attribut vec3 aVertexPosition;
attribut vec2 aTextureCoord;

// dessa är obligatoriska uniformer som de lib-apparater och som innehåller vår modell visa och projektion matris
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

// om du vill skicka din vertex och textur koordinater till fragment shader
varying vec3 vVertexPosition;
varierande vec2 vTextureCoord;

void main() {
// get the vertex position från dess attribut
vec3 vertexPosition = aVertexPosition;
// ange sin position baserad på projektionen och modell-vy-matrisen
gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);

// ange varyings
vTextureCoord = aTextureCoord;
vVertexPosition = vertexPosition;
}
</script>

Nu är vår fragment shader. Det är där vi kommer att lägga till en liten förskjutning verkan bygger på våra gången enhetliga och struktur koordinater.

<!– fragment shader –>
<script id=”plane-fs-typ”=”x-shader/x-fragment”>
#ifdef GL_ES
precision mediump float;
#endif

// hämta våra varyings
varying vec3 vVertexPosition;
varierande vec2 vTextureCoord;

// den uniform som vi förklarade i vår javascript
uniform flyta uTime;

// vår struktur sampler (detta är den lib standard namn, men det kan ändras)
uniform sampler2D uSampler0;

void main() {
// hämta vår struktur coords
vec2 textureCoord = vTextureCoord;

// rubba vår pixlar längs båda axel baserad på vår tid uniform och textur UVs
// detta kommer att skapa en typ av vatten ytan effekt
// försöker att kommentera en rad eller ändra konstanter för att se hur det förändrar effekt
// påminnelse : texturer koordinater är allt från 0,0 till 1,0 på båda axeln
const float PI = 3.141592;

textureCoord.x += (
synd(textureCoord.x * 10.0 + ((uTime * (PI / 3.0)) * 0.031))
+ sin(textureCoord.y * 10.0 + ((uTime * (PI / 2.489)) * 0.017))
) * 0.0075;

textureCoord.y += (
synd(textureCoord.y * 20.0 + ((uTime * (PI / 2.023)) * 0.023))
+ sin(textureCoord.x * 20.0 + ((uTime * (PI / 3.1254)) * 0.037))
) * 0.0125;

gl_FragColor = texture2D(uSampler0, textureCoord);
}
</script>

Et voilà! Du är allt gjort, och om allt gick väl, bör du vara när man ser något som detta.

Se Pennan curtains.js grundläggande plan av Martin Laxenaire (@martinlaxenaire) på CodePen.

Lägga till 3D-och interaktioner

Okej, det är ganska coolt så långt, men vi startade det här inlägget talar om 3D och interaktioner, så låt oss titta på hur vi kunde lägga dem i.

Om vertexpunkter

För att lägga till en 3D-effekt vi skulle byta plan hörn position inne i vertex shader. Men i vårt första exempel, vi gjorde inte ange hur många hörn av vår planet ska ha, så det var skapad med en standard geometri innehåller sex hörn bildar två trianglar :

För att få anständiga 3D-animationer, vi skulle behöva fler trianglar, alltså mer hörn:

Denna plan har fem segment längs dess bredd och fem segment längs dess höjd. Som ett resultat, vi har 50 trianglar och 150 totalt hörn.

Refactoring vår JavaScript

Lyckligtvis är det lätt att ange vår planet definition som den kan ställas in i vår ursprungliga parametrarna.

Vi kommer också att lyssna på musens läge att lägga lite av interaktion. För att göra det ordentligt, vi kommer att få vänta i planet för att vara redo, konvertera vår mus dokument koordinater till vår WebGL klipp utrymme koordinater och skicka dem till de shaders som en uniform.

// vi använder fönstret onload-händelse här, men detta är inte obligatoriskt
fönster.onload = function() {
// spår musen positioner för att skicka det till shaders
var mousePosition = {
x: 0,
y: 0,
};

// klara-id för den div som kommer att avsluta canvas att sätta upp våra WebGL sammanhang och lägg duken på våra omslag
var webGLCurtain = nya Gardiner(“bakgrund”);

// hämta vår planet element
var planeElement = dokument.getElementsByClassName(“plan”)[0];

// set våra ursprungliga parametrarna (grundläggande uniformer)
var params = {
vertexShaderID: “plan-vs”, // vertex shader-ID
fragmentShaderID: “plan-fs”, // våra framgent shader-ID
widthSegments: 20,
heightSegments: 20, // vi har nu 20*20*6 = 2400 hörn !
uniformer: {
tid: {
namn: “uTime”, // enhetliga namn som kommer att skickas till våra shaders
typ: “1f”, // detta innebär att vår uniform är en float
värde: 0,
},
mousePosition: { // musens position.
namn: “uMousePosition”,
typ: “2f”, // märka detta är en längd 2 utbud av flöten
värde: [mousePosition.x, mousePosition.y],
},
mouseStrength: { // effektens styrka (vi kommer att dämpa den om musen stannar)
namn: “uMouseStrength”, // enhetliga namn som kommer att skickas till våra shaders
typ: “1f”, // detta innebär att vår uniform är en float
värde: 0,
},

}
}

// skapa vår planet mesh
var plan = webGLCurtain.addPlane(planeElement, params);

// när vår planet är redo, vi kan börja att lyssna på mus (mouse)/touch händelser och uppdatera sina uniformer
– planet.onReady(function() {
// ange ett synfält som är 35 till exagerate perspektiv
// vi kunde ha gjort det direkt i första params
– planet.setPerspective(35);
// lyssna vår mus/touch händelser på hela dokumentet
// vi kommer att passera den plan som andra argument av vår funktion
// vi kan hantera flera plan på det sättet
dokumentet.organ.addEventListener(“mousemove”, function(e) {
handleMovement(e, plan);
});
dokumentet.organ.addEventListener(“touchmove”, function(e) {
handleMovement(e, plan);
});
}).onRender(function() {
// uppdatering av vår tid enhetligt värde
– planet.uniformer.tid.värde++;
// att kontinuerligt minska musen styrka
– planet.uniformer.mouseStrength.värde = Matematik.max(0, plan.uniformer.mouseStrength.värde – 0.0075);
});

// hantera musen flytta händelse
funktion handleMovement(e, plan) {
// touch händelse
om e.targetTouches) {
mousePosition.x = e.targetTouches[0].clientX;
mousePosition.y = e.targetTouches[0].clientY;
}
// mus händelse
else {
mousePosition.x = e.clientX;
mousePosition.y = e.clientY;
}
// konvertera vår mus/touch ställning till koordinater i förhållande till det hörn av planet
var mouseCoords = plan.mouseToPlaneCoords(mousePosition.x, mousePosition.y);
// uppdatering av vår mus position uniform
– planet.uniformer.mousePosition.värde = [mouseCoords.x, mouseCoords.y];

// tilldela musen styrka
– planet.uniformer.mouseStrength.värde = 1;
}

}

Nu när vår JavaScript är gjort, vi skriva om våra shaders så att de kommer att använda vår mus position uniform.

Refactoring shaders

Låt oss titta på våra vertex shader först. Vi har tre uniformer som vi kan använda för våra effekt:

  1. den tid som är ständigt ökande
  2. musens position.
  3. vår mus styrka, som är ständigt minskar tills nästa musen för att flytta

Vi kommer att använda alla tre av dem för att skapa en typ av 3D krusning effekt.

<script id=”plane-vs” typ=”x-shader/x-vertex”>
#ifdef GL_ES
precision mediump float;
#endif

// dessa är de obligatoriska attribut som sätter lib
attribut vec3 aVertexPosition;
attribut vec2 aTextureCoord;

// dessa är obligatoriska uniformer som de lib-apparater och som innehåller vår modell visa och projektion matris
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

// vår tid uniform
uniform flyta uTime;

// vår mus position uniform
uniform vec2 uMousePosition;

// vår mus styrka
uniform flyta uMouseStrength;

// om du vill skicka din vertex och textur koordinater till fragment shader
varying vec3 vVertexPosition;
varierande vec2 vTextureCoord;

void main() {
vec3 vertexPosition = aVertexPosition;

// get avståndet mellan våra vertex och musens position.
float distanceFromMouse = avstånd(uMousePosition, vec2(vertexPosition.x, vertexPosition.y));

// detta kommer att definiera hur nära de ringar som kommer att vara från varandra. Ju större nummer, desto fler ringar får du
float rippleFactor = 6.0;

// räkna våra ringar på vattnet
float rippleEffect = cos(rippleFactor * (distanceFromMouse – (uTime / 120.0)));

// räkna våra snedvriden effekt
float distortionEffect = rippleEffect * uMouseStrength;

// tillämpa det på våra vertex position
vertexPosition += distortionEffect / 15.0;

gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);

// varyings
vTextureCoord = aTextureCoord;
vVertexPosition = vertexPosition;
}
</script>

För fragment shader, vi kommer att hålla det enkelt. Vi kommer att falska ljus och skuggor baserat på varje vertex position:

<script id=”plane-fs-typ”=”x-shader/x-fragment”>
#ifdef GL_ES
precision mediump float;
#endif

// hämta våra varyings
varying vec3 vVertexPosition;
varierande vec2 vTextureCoord;

// vår struktur sampler (detta är den lib standard namn, men det kan ändras)
uniform sampler2D uSampler0;

void main() {
// hämta vår struktur coords
vec2 textureCoords = vTextureCoord;

// använd vår struktur
vec4 finalColor = texture2D(uSampler0, textureCoords);

// falska skuggor baserat på vertex position längs Z-axeln
finalColor.rgb -= clamp(-vVertexPosition.z, 0.0, 1.0);

// falska ljus som bygger på vertex position längs Z-axeln
finalColor.rgb += clamp(vVertexPosition.z, 0.0, 1.0);

// hantering premultiplied alpha (användbart om vi skulle använda en png med öppenhet)
finalColor = vec4(finalColor.rgb * finalColor.en, finalColor.a).

gl_FragColor = finalColor;
}
</script>

Och det har du!

Se Pennan curtains.js ringar på vattnet exempel av Martin Laxenaire (@martinlaxenaire) på CodePen.

Med dessa två enkla exempel, vi har sett hur man skapar en plan och interagera med den.

Videor och förskjutning shaders

Vår sista exemplet kommer att skapa en grundläggande fullskärm video bildspel med hjälp av en förskjutning shader för att öka övergångar.

Förskjutningen shader koncept

Förskjutningen shader kommer att skapa en trevlig snedvriden effekt. Det kommer att skrivas i våra fragment shader med hjälp av en gråskala bilden och kommer att kompensera pixel koordinater av de filmer som bygger på den struktur RGB-värden. Här är bilden som vi kommer att använda:

Effekten kommer att beräknas baserat på varje pixel RGB-värde, med en svart pixel är [0, 0, 0] och en vit pixel [1, 1, 1] (GLSL motsvarande för [255, 255, 255]). För att förenkla, kommer vi endast att använda den röda kanalen värde, som med en bild i gråskala röd, grön och blå är alltid lika.

Du kan prova att skapa din egen bild i gråskala (det fungerar bra med geometrisk form ) för att få din unika övergångseffekt.

Flera texturer och videor

En planet kan ha mer än en textur helt enkelt genom att lägga till flera taggar bild. Denna gång, i stället för bilder som vi vill använda för videor. Vi har bara att ersätta <img / > – taggarna med en <video /> en. Men det finns två saker att veta när det gäller video:

  • Videon kommer alltid att passa de exakta måtten på planet, vilket betyder att ditt flyg har har samma bredd/höjd-förhållande som din video. Detta är inte en big deal tho eftersom det är lätt att hantera med CSS.
  • På mobila enheter, vi kan inte spela upp automatiskt videor utan att användaren gest, som en click-händelse. Det är därför säkrare att lägga till en “enter site” – knappen för att visa och starta våra filmer.

HTML –

HTML är fortfarande ganska enkelt. Vi kommer att skapa vår canvas div omslag, vår planet div som innehåller texturer och en knapp för att utlösa video spela upp automatiskt. Bara observera användningen av data-sampler attribut på bild och video taggar—det kommer att vara användbar i vår fragment shader.

<body>
<div id=”duk”></div>
<!– detta div-kommer att hantera fullscreen video storlekar och positioner –>
<div class=”plane-wrapper”>
<div class=”plane”>
<!– observera här att vi använder data-sampler-attributet för att nämna våra sampler uniformer –>
<img src=”path/to/displacement.jpg” data-sampler=”förskjutning” />
<video src=”sökväg/till/video.mp4 – ” data-sampler=”firstTexture”></video>
<video src=”sökväg/till/video-2.mp4 – ” data-sampler=”secondTexture”></video>
</div>
</div>

<div id=”in-site-wrapper”>
<span id=”retur-webbplats”>
Klicka för att ange plats
</span>
</div>
</body>
CSS

Stilmallen kommer att hantera ett par saker: visa knappen och gömma duken innan användaren har angett den plats, storlek och position vår planet-omslag div för att hantera helskärmsläge lyhörd videor.

@media screen {

body {
margin: 0;
font-size: 18px;
font-family: ‘PT Sans’, Verdana, sans-serif;
bakgrund: #212121;
line-height: 1.4;
höjd: 100vh;
bredd: 100vw;
overflow: hidden;
}

/*** canvas ***/

#duk {
position: absolute;
top: 0;
rätt: 0;
bottom: 0;
left: 0;
z-index: 10;

/* gömma duken tills användaren klickar på knappen */
opacitet: 0;
övergång: opacitet 0,5 s lätthet.
}

/* visa arbetsytan */
.video-igång #duk {
opacitet: 1;
}

.plan-wrapper {
position: absolute;

/* centrera vårt plan omslag */
vänster: 50%;
topp: 50%;
förändra: översätta(-50%, -50%);
z-index: 15;
}

.plan {
position: absolute;
top: 0;
rätt: 0;
bottom: 0;
left: 0;

/* tala om för användaren att han kan klicka på planet */
cursor: pointer;
}

/* dölja den ursprungliga bilden och video */
.planet img, .planet video {
display: none;
}

/* centrera-knappen */
#in-site-wrapper {
display: flex;
motivera-innehåll: center;
align-objekt: center;
align-innehåll: center;
position: absolute;
top: 0;
rätt: 0;
bottom: 0;
left: 0;
z-index: 30;

/* dölj-knappen tills allt är klart */
opacitet: 0;
övergång: opacitet 0,5 s lätthet.
}

/* visa-knappen */
.gardiner-redo #in-site-wrapper {
opacitet: 1;
}

/* dölj knappen efter klicket händelse */
.gardiner-redo.video-igång #in-site-wrapper {
opacitet: 0;
pekare-händelser: none;
}

#ange plats {
padding: 20px;
färg: vit.
bakgrund: #ee6557;
max-width: 200px;
text-align: center;
cursor: pointer;
}

}

/* fullscreen video lyhörd */
@media screen and (max-bildförhållande: 1920/1080) {
.plan-wrapper {
höjd: 100vh;
bredd: 177vh;
}
}

@media screen och (min-bildförhållande: 1920/1080) {
.plan-wrapper {
bredd: 100vw;
höjd: 56.25 vw,
}
}
JavaScript

Som för JavaScript, vi kommer att gå ut så här:

  • Ange några variabler för att lagra våra bildspel staten
  • Skapa Gardiner objekt och lägga till planet till det
  • När planet är redo, lyssna till en click-händelse för att börja vår video uppspelning (observera användningen av playVideos () – metoden). Lägga till en annan klicka på händelsen för att växla mellan de två filmer.
  • Uppdatera vår övergång timer uniform inuti onRender () – metoden

fönster.onload = function() {

// här kommer vi att hantera konsistens som är synligt och timer för att övergången mellan bilder
var activeTexture = 1;
var transitionTimer = 0;

// set upp våra WebGL sammanhang och lägg duken på våra omslag
var webGLCurtain = nya Gardiner(“bakgrund”);

// hämta vår planet element
var planeElements = dokument.getElementsByClassName(“plan”);

// lite grundläggande parametrar
var params = {
vertexShaderID: “plan-vs”,
fragmentShaderID: “plan-fs”,
imageCover: false, // våra förskjutning textur har att passa planet
uniformer: {
transitionTimer: {
namn: “uTransitionTimer”,
typ: “1f”,
värde: 0,
},
},
}

var plan = webGLCurtain.addPlane(planeElements[0], params);

// skapa vår planet
– planet.onReady(function() {
// visa-knappen
dokumentet.organ.classList.lägga till(“gardiner-ready”);

// när vårt plan är klar ska vi lägga till en click-händelse lyssnare som kommer att växla det aktiva konsistens värdet
planeElements[0].addEventListener(“click”, function() {
om(activeTexture == 1) {
activeTexture = 2;
}
else {
activeTexture = 1;
}
});

// klicka på för att spela upp videoklippen
dokumentet.getElementById(“in-site”).addEventListener(“click”, function() {
// visar duk och dölja knappen
dokumentet.organ.classList.lägga till(“video-igång”);

// spela våra videor
– planet.playVideos();
}, false);

}).onRender(function() {
// för att öka eller minska vår timer som baseras på den aktiva konsistens värdet
// på 60fps detta ska pågå en sekund
om(activeTexture == 2) {
transitionTimer = Matematik.min(60, transitionTimer + 1);
}
else {
transitionTimer = Matematik.max(0, transitionTimer – 1);
}
// uppdatering av vår övergång timer uniform
– planet.uniformer.transitionTimer.värde = transitionTimer;
});
}
Shaders

Det är där all magi kommer ske. Som i vårt första exempel, vertex shader kommer inte att göra mycket och du har att fokusera på fragment shader som kommer att skapa en “dyk i” effekt:

<script id=”plane-vs” typ=”x-shader/x-vertex”>
#ifdef GL_ES
precision mediump float;
#endif

// default obligatoriska variabler
attribut vec3 aVertexPosition;
attribut vec2 aTextureCoord;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;

// varyings
varying vec3 vVertexPosition;
varierande vec2 vTextureCoord;

// custom uniformer
uniform flyta uTransitionTimer;

void main() {

vec3 vertexPosition = aVertexPosition;

gl_Position = uPMatrix * uMVMatrix * vec4(vertexPosition, 1.0);

// varyings
vTextureCoord = aTextureCoord;
vVertexPosition = vertexPosition;
}
</script>

<script id=”plane-fs-typ”=”x-shader/x-fragment”>
#ifdef GL_ES
precision mediump float;
#endif

varying vec3 vVertexPosition;
varierande vec2 vTextureCoord;

// custom uniformer
uniform flyta uTransitionTimer;

// våra texturer provtagare
// lägg märke till hur det matchar våra data-sampler attribut
uniform sampler2D firstTexture;
uniform sampler2D secondTexture;
uniform sampler2D förflyttning.

void main( void ) {
// vår struktur coords
vec2 textureCoords = vec2(vTextureCoord.x, vTextureCoord.y);

// våra förskjutning konsistens
vec4 displacementTexture = texture2D(förskjutning, textureCoords);

// våra förskjutning faktor är en float varierande från 1 till 0 på timer
float displacementFactor = 1.0 – (cos(uTransitionTimer / (60.0 / 3.141592)) + 1.0) / 2.0;

// den effekt faktor som kommer att avgöra vilken väg vi vill ersätta våra pixlar
// den längre från centrum av videor, desto starkare blir det
vec2 effectFactor = vec2((textureCoords.x – 0.5) * 0.75, (textureCoords.y – 0.5) * 0.75);

// räkna våra fördrivna koordinater till vår första video
vec2 firstDisplacementCoords = vec2(textureCoords.x – displacementFactor * (displacementTexture.r * effectFactor.x), textureCoords.y – displacementFactor * (displacementTexture.r * effectFactor.y));
// motsatt förskjutning effekt på den andra videon
vec2 secondDisplacementCoords = vec2(textureCoords.x – (1.0 – displacementFactor) * (displacementTexture.r * effectFactor.x), textureCoords.y – (1.0 – displacementFactor) * (displacementTexture.r * effectFactor.y));

// applicera texturer
vec4 firstDistortedColor = texture2D(firstTexture, firstDisplacementCoords);
vec4 secondDistortedColor = texture2D(secondTexture, secondDisplacementCoords);

// blanda både strukturer som bygger på våra förskjutning faktor
vec4 finalColor = mix(firstDistortedColor, secondDistortedColor, displacementFactor);

// hantering premultiplied alpha
finalColor = vec4(finalColor.rgb * finalColor.en, finalColor.a).

// använd vår shader
gl_FragColor = finalColor;
}
</script>

Här är vår lilla video bildspel med en cool övergången effekt:

Se Pennan curtains.js video bildspel av Martin Laxenaire (@martinlaxenaire) på CodePen.

Detta exempel är ett bra sätt att visa hur du skapar ett bildspel med curtains.js: du kanske vill använda bilder istället för filmer, ändra förskjutningen textur, ändra fragment shader eller även lägga till fler bilder…

Att gå djupare

Vi har bara skrapat på ytan av vad som är möjligt med curtains.js. Du kan försöka att skapa flera plan med en cool musen över effekt för din artikel tummarna för exempel. Möjligheterna är nästan oändliga.

Om du vill se mer exempel som täcker samtliga dessa grunder användning, kan du kontrollera bibliotekets hemsida eller GitHub-repo.

Jetpack WordPress plugin som körs på denna webbplats, driver inte bara relaterade inlägg nedan, men säkerhet och backup, Wiki-stöd, sök på sajten, kommentera form, sociala nätverk, och mycket mer!