render GLSL Transitions – transition effects performed with WebGL.
A GLSL Transition is a fragment shader that MUST have 4 uniforms:
uniform sampler2D from, to;
uniform float progress;
uniform vec2 resolution;
A GLSL Transition draws a transition between from
and to
textures
when progress
moves between 0.0 and 1.0.
A GLSL Transition is allowed (and encouraged) to have extra uniforms.
var baboon = require("baboon-image");
var lena = require("lena");
var createTexture = require("gl-texture2d");
var createTransition = require("glsl-transition");
var CubeTransition = { // from "glsl-transitions"
"glsl" : "#ifdef GL_ES\nprecision highp float;\n#endif\nuniform sampler2D from, to;\nuniform float progress;\nuniform vec2 resolution;\n\nuniform float persp;\nuniform float unzoom;\nuniform float reflection;\nuniform float floating;\n\nvec2 project (vec2 p) {\n return p * vec2(1.0, -1.2) + vec2(0.0, -floating/100.);\n}\n\nbool inBounds (vec2 p) {\n return all(lessThan(vec2(0.0), p)) && all(lessThan(p, vec2(1.0)));\n}\n\nvec4 bgColor (vec2 p, vec2 pfr, vec2 pto) {\n vec4 c = vec4(0.0, 0.0, 0.0, 1.0);\n pfr = project(pfr);\n if (inBounds(pfr)) {\n c += mix(vec4(0.0), texture2D(from, pfr), reflection * mix(1.0, 0.0, pfr.y));\n }\n pto = project(pto);\n if (inBounds(pto)) {\n c += mix(vec4(0.0), texture2D(to, pto), reflection * mix(1.0, 0.0, pto.y));\n }\n return c;\n}\n\n// p : the position\n// persp : the perspective in [ 0, 1 ]\n// center : the xcenter in [0, 1] \\ 0.5 excluded\nvec2 xskew (vec2 p, float persp, float center) {\n float x = mix(p.x, 1.0-p.x, center);\n return (\n (\n vec2( x, (p.y - 0.5*(1.0-persp) * x) / (1.0+(persp-1.0)*x) )\n - vec2(0.5-distance(center, 0.5), 0.0)\n )\n * vec2(0.5 / distance(center, 0.5) * (center<0.5 ? 1.0 : -1.0), 1.0)\n + vec2(center<0.5 ? 0.0 : 1.0, 0.0)\n );\n}\n\nvoid main() {\n vec2 op = gl_FragCoord.xy / resolution.xy;\n float uz = unzoom * 2.0*(0.5-distance(0.5, progress));\n vec2 p = -uz*0.5+(1.0+uz) * op;\n vec2 fromP = xskew(\n (p - vec2(progress, 0.0)) / vec2(1.0-progress, 1.0),\n 1.0-mix(progress, 0.0, persp),\n 0.0\n );\n vec2 toP = xskew(\n p / vec2(progress, 1.0),\n mix(pow(progress, 2.0), 1.0, persp),\n 1.0\n );\n if (inBounds(fromP)) {\n gl_FragColor = texture2D(from, fromP);\n }\n else if (inBounds(toP)) {\n gl_FragColor = texture2D(to, toP);\n }\n else {\n gl_FragColor = bgColor(op, fromP, toP);\n }\n}",
"uniforms": { "persp": 0.7, "unzoom": 0.3, "reflection": 0.4, "floating": 3.0 }
};
var transition, from, to;
var shell = require("gl-now")();
shell.on("gl-init", function() {
var gl = shell.gl;
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
transition = createTransition(gl, CubeTransition.glsl);
to = createTexture(gl, baboon.transpose(1, 0));
from = createTexture(gl, lena.transpose(1, 0));
});
shell.on("gl-render", function () {
transition.render((Date.now() / 1000) % 1, from, to, CubeTransition.uniforms);
});
var Q = require("q");
var Qimage = require("qimage");
var raf = require("raf");
var GlslTransitions = require("glsl-transitions").sort(function (a, b) {
return b.stars - a.stars;
});
var createTexture = require("gl-texture2d");
var createTransition = require("glsl-transition");
Q.all([
Qimage.anonymously("http://i.imgur.com/N8a9CkZ.jpg"),
Qimage.anonymously("http://i.imgur.com/MQtLWbD.jpg")
]).spread(function (fromImage, toImage) {
var canvas = document.createElement("canvas");
canvas.style.display = "block";
canvas.width = 600;
canvas.height = 400;
var gl = canvas.getContext("webgl");
if (!gl) throw new Error("webgl context is not supported.");
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
var from = createTexture(gl, fromImage);
var to = createTexture(gl, toImage);
var transitionItem, transition;
raf(function loop (t) {
raf(loop);
if (transition) {
var progress = (t/1500) % 2;
if (progress > 1) progress = 2 - progress; // backwards
transition.render(progress, from, to, transitionItem.uniforms);
}
});
function setTransition (i) {
transitionItem = GlslTransitions[i];
if (transition) transition.dispose();
transition = createTransition(gl, transitionItem.glsl);
}
var select = document.createElement("select");
select.style.width = "600px";
GlslTransitions.forEach(function (t) {
var option = document.createElement("option");
option.textContent = t.name;
select.appendChild(option);
});
select.addEventListener("change", function () {
setTransition(select.selectedIndex);
});
setTransition(select.selectedIndex);
document.body.innerHTML = "";
document.body.appendChild(select);
document.body.appendChild(canvas);
}).done();
document.body.innerHTML = "Loading...";
GLSL Transitions performed between Videos
var raf = require("raf");
var createTexture = require("gl-texture2d");
var createTransition = require("../..");
var GlslTransitions = require("glsl-transitions").sort(function (a, b) {
return b.stars - a.stars;
});
var videos = require("./videos");
videos.then(function (videos) {
var canvas = document.createElement("canvas");
canvas.style.display = "block";
canvas.width = 600;
canvas.height = 400;
var gl = canvas.getContext("webgl");
if (!gl) throw new Error("webgl context is not supported.");
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
var from = createTexture(gl, videos[0]);
var to = createTexture(gl, videos[1]);
var transitionItem, transition;
var duration = 1500;
videos.forEach(function (video) {
video.loop = true;
video.play();
});
raf(function loop (t) {
raf(loop);
var i = Math.floor(t / duration) % videos.length;
var j = (i + 1) % videos.length;
from.setPixels(videos[i]);
to.setPixels(videos[j]);
var progress = (t % duration) / duration;
if (transition) transition.render(progress, from, to, transitionItem.uniforms);
});
function setTransition (i) {
transitionItem = GlslTransitions[i];
if (transition) transition.dispose();
transition = createTransition(gl, transitionItem.glsl);
}
var select = document.createElement("select");
select.style.width = "600px";
GlslTransitions.forEach(function (t) {
var option = document.createElement("option");
option.textContent = t.name;
select.appendChild(option);
});
select.addEventListener("change", function () {
setTransition(select.selectedIndex);
});
setTransition(select.selectedIndex);
document.body.innerHTML = "";
document.body.appendChild(select);
document.body.appendChild(canvas);
}).done();
document.body.innerHTML = "Loading...";