Skip to content

Instantly share code, notes, and snippets.

@philogb
Created October 5, 2011 22:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save philogb/1265902 to your computer and use it in GitHub Desktop.
Save philogb/1265902 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<title>WebGL Shader Lab</title>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aPos;
attribute vec2 aTexCoord;
varying vec2 pixel;
void main(void) {
gl_Position = vec4(aPos, 1.);
pixel = aTexCoord;
}
</script>
<script id="shader-fs-blur-horizontal" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
// original shader from http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/
// horizontal blur fragment shader
uniform sampler2D src_tex;
varying vec2 pixel;
uniform vec2 pixelSize;
void main(void) // fragment
{
float h = pixelSize.x;
vec4 sum = vec4(0.0);
sum += texture2D(src_tex, vec2(pixel.x - 4.0*h, pixel.y) ) * 0.05;
sum += texture2D(src_tex, vec2(pixel.x - 3.0*h, pixel.y) ) * 0.09;
sum += texture2D(src_tex, vec2(pixel.x - 2.0*h, pixel.y) ) * 0.12;
sum += texture2D(src_tex, vec2(pixel.x - 1.0*h, pixel.y) ) * 0.15;
sum += texture2D(src_tex, vec2(pixel.x + 0.0*h, pixel.y) ) * 0.16;
sum += texture2D(src_tex, vec2(pixel.x + 1.0*h, pixel.y) ) * 0.15;
sum += texture2D(src_tex, vec2(pixel.x + 2.0*h, pixel.y) ) * 0.12;
sum += texture2D(src_tex, vec2(pixel.x + 3.0*h, pixel.y) ) * 0.09;
sum += texture2D(src_tex, vec2(pixel.x + 4.0*h, pixel.y) ) * 0.05;
gl_FragColor.xyz = sum.xyz/0.98; // normalize
gl_FragColor.a = 1.;
}
</script>
<script id="shader-fs-blur-vertical" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
// original shader from http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/
// vertical blur fragment shader
uniform sampler2D src_tex;
varying vec2 pixel;
uniform vec2 pixelSize;
void main(void) // fragment
{
float v = pixelSize.y;
vec4 sum = vec4(0.0);
sum += texture2D(src_tex, vec2(pixel.x, - 4.0*v + pixel.y) ) * 0.05;
sum += texture2D(src_tex, vec2(pixel.x, - 3.0*v + pixel.y) ) * 0.09;
sum += texture2D(src_tex, vec2(pixel.x, - 2.0*v + pixel.y) ) * 0.12;
sum += texture2D(src_tex, vec2(pixel.x, - 1.0*v + pixel.y) ) * 0.15;
sum += texture2D(src_tex, vec2(pixel.x, + 0.0*v + pixel.y) ) * 0.16;
sum += texture2D(src_tex, vec2(pixel.x, + 1.0*v + pixel.y) ) * 0.15;
sum += texture2D(src_tex, vec2(pixel.x, + 2.0*v + pixel.y) ) * 0.12;
sum += texture2D(src_tex, vec2(pixel.x, + 3.0*v + pixel.y) ) * 0.09;
sum += texture2D(src_tex, vec2(pixel.x, + 4.0*v + pixel.y) ) * 0.05;
gl_FragColor.xyz = sum.xyz/0.98;
gl_FragColor.a = 1.;
}
</script>
<script id="shader-fs-advance" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D sampler_prev;
uniform sampler2D sampler_prev_n;
uniform sampler2D sampler_blur;
uniform sampler2D sampler_blur2;
uniform sampler2D sampler_blur3;
uniform sampler2D sampler_blur4;
uniform sampler2D sampler_noise;
uniform sampler2D sampler_noise_n;
varying vec2 pixel;
uniform vec2 pixelSize;
uniform vec4 rnd;
uniform vec2 mouse;
uniform float time;
uniform float fps;
uniform float x1;
uniform float y1;
uniform float d1;
uniform float x2;
uniform float y2;
uniform float d2;
float line_segment(vec2 domain, vec2 p1, float d1, vec2 p2, float d2){
float h = 1./(p2.x-p1.x); // helper registers
float h1 = (p2.y-p1.y)*h;
float h2 = 1./h1;
float xs = (-p1.y+h1*p1.x+h2*domain.x+domain.y)/(h2+h1);// coordinates of the point on the line between p1 and p2,
float ys = -h2*(xs-domain.x)+domain.y; // ^ orthogonally to the given point in the domain
float d = length(domain-vec2(xs,ys)); // the orthogonal distance from the domain point to the line (unlimited)
float s = 0.; // distance from domain point to p1 relative to p2
if(p2.x == p1.x){ // division by zero fix
d = abs(domain.x - p1.x);
s = (p1.y-ys)/(p1.y-p2.y);
}else{
s = (xs-p1.x)*h;
}
d = clamp(d*(d1*(1.-s)+d2*s),0., 1.); // adjusting the line thickness using a linear interpolation with s
float m1 = 0.; if(s > 0.) m1 = 1.; // masking out the segment between p1 and p2
float m2 = 0.; if(s < 1.) m2 = 1.;
float result = clamp( m1*m2-d, 0., 1.); // return result as 1-distance in the range [0..1]
result = clamp(1.-length(domain-vec2(p1.x,p1.y))*d1-m1, result, 1.); // round corners if you will (half circles)
//result = clamp(1.-length(domain-vec2(p2.x,p2.y))*d2-m2, result, 1.);
return result;
}
uniform float sin1;
uniform float cos1;
uniform float scale1;
uniform float sin2;
uniform float cos2;
uniform float scale2;
uniform float sin3;
uniform float cos3;
vec2 complex_mul(vec2 factorA, vec2 factorB){
return vec2( factorA.x*factorB.x - factorA.y*factorB.y, factorA.x*factorB.y + factorA.y*factorB.x);
}
float square_mask(vec2 domain){
return (domain.x <= 1. && domain.x >= 0. && domain.y <= 1. && domain.y >= 0.) ? 1. : 0.;
}
void main(void) {
vec3 color_increment =vec3(0.004,0.008,0.);
vec2 pos1 = vec2(x1,y1);
vec2 pos2 = vec2(x2,y2);
vec2 c = vec2(0.5);
gl_FragColor.xyz = vec3(1.-line_segment(pixel, pos1, d1, pos2, d2));
// complex multiplication to rotate
vec2 uv_stem_feedback = complex_mul((pixel-pos2),vec2(cos1,sin1)*vec2(scale1)) + pos1;
vec3 stem_feedback = texture2D( sampler_prev, uv_stem_feedback).xyz + color_increment;
vec3 stem_feedback_mask = vec3(square_mask(uv_stem_feedback));
stem_feedback *= stem_feedback_mask;
stem_feedback += vec3(1.)-stem_feedback_mask;
vec2 uv_left_arm_feedback = complex_mul((pixel-pos2),vec2(cos2,sin2)*vec2(scale2)) + pos1;
vec3 left_arm_feedback = texture2D( sampler_prev, uv_left_arm_feedback).xyz + color_increment;
vec3 left_arm_feedback_mask = vec3(square_mask(uv_left_arm_feedback));
left_arm_feedback *= left_arm_feedback_mask;
left_arm_feedback += vec3(1.)-left_arm_feedback_mask;
vec2 uv_right_arm_feedback = complex_mul((pixel-pos2),vec2(cos3,sin3)*vec2(scale2)) + pos1;
vec3 right_arm_feedback = texture2D( sampler_prev, uv_right_arm_feedback).xyz + color_increment;
vec3 right_arm_feedback_mask = vec3(square_mask(uv_right_arm_feedback));
right_arm_feedback *= right_arm_feedback_mask;
right_arm_feedback += vec3(1.)-right_arm_feedback_mask;
gl_FragColor.xyz = min( gl_FragColor.xyz, min(stem_feedback, min(left_arm_feedback, right_arm_feedback)));
gl_FragColor.xyz = mix( gl_FragColor.xyz, texture2D(sampler_prev, pixel).xyz, vec3(0.42)); // sort of a motion blur
gl_FragColor.a = 1.;
}
</script>
<script id="shader-fs-composite" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D sampler_prev;
uniform sampler2D sampler_prev_n;
uniform sampler2D sampler_blur;
uniform sampler2D sampler_blur2;
uniform sampler2D sampler_blur3;
uniform sampler2D sampler_blur4;
uniform sampler2D sampler_noise;
uniform sampler2D sampler_noise_n;
varying vec2 pixel;
uniform vec2 pixelSize;
uniform vec4 rnd;
uniform vec2 mouse;
uniform float time;
uniform float fps;
void main(void) {
gl_FragColor = texture2D(sampler_prev, pixel); // copy
gl_FragColor.a = 1.;
}
</script>
<script id="shader-fs-copy" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D sampler_prev;
varying vec2 pixel;
void main(void) {
gl_FragColor = texture2D(sampler_prev, pixel);
gl_FragColor.a = 1.;
}
</script>
<script type="text/javascript">
function BrowserSize() {
if (typeof (window.innerWidth) == 'number') {
//Non-IE
this.width = window.innerWidth;
this.height = window.innerHeight;
} else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
//IE 6+ in 'standards compliant mode'
this.width = document.documentElement.clientWidth;
this.height = document.documentElement.clientHeight;
} else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
//IE 4 compatible
this.width = document.body.clientWidth;
this.height = document.body.clientHeight;
}
}
BrowserSize.prototype.width;
BrowserSize.prototype.height;
function getShader(gl, id) {
var shaderScript = document.getElementById(id);
var str = "";
var k = shaderScript.firstChild;
while (k) {
if (k.nodeType == 3)
str += k.textContent;
k = k.nextSibling;
}
var shader;
if (shaderScript.type == "x-shader/x-fragment")
shader = gl.createShader(gl.FRAGMENT_SHADER);
else if (shaderScript.type == "x-shader/x-vertex")
shader = gl.createShader(gl.VERTEX_SHADER);
else
return null;
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS) == 0)
alert(gl.getShaderInfoLog(shader));
return shader;
}
requestAnimFrame = (function() {
return window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback, element) {
setTimeout(callback, 1000 / 60);
};
})();
var gl;
var prog_copy;
var prog_advance;
var prog_composite;
var prog_blur_horizontal;
var prog_blur_vertical;
var FBO_main;
var FBO_main2;
var FBO_noise;
var FBO_blur;
var FBO_blur2;
var FBO_blur3;
var FBO_blur4;
var FBO_helper;
var FBO_helper2;
var FBO_helper3;
var FBO_helper4;
var texture_main_l; // main, linear
var texture_main_n; // main, nearest (accurate pixel access on the same buffer)
var texture_main2_l; // main double buffer, linear
var texture_main2_n; // main double buffer, nearest (accurate pixel access on the same buffer)
var texture_helper; // needed for multi-pass shader programs (2-pass Gaussian blur)
var texture_helper2; // (1/4 resolution )
var texture_helper3; // (1/16 resolution )
var texture_helper4; // (1/256 resolution )
var texture_blur; // full resolution blur result
var texture_blur2; // double blur
var texture_blur3; // quad blur
var texture_blur4; // really low resolution - use wisely ^^
var texture_noise_n; // noise pixel accurate
var texture_noise_l; // noise interpolated pixel access
var halted = false;
var delay = 3;
var it = 1;
var frames = 0;
var fps = 60; // no hurdle for DX10 graphics cards
var time = 0;
var mouseX = 0.5;
var mouseY = 0.5;
var animation;
var timer;
// texture size (must be powers of two, remember 2048x1024 flat could also be a 128x128x128 voxel)
var sizeX = 2048;
var sizeY = 1024; // 2048x1024 flat or 128x128x128 cube
// viewport size
var viewX = 1024;
var viewY = 1024;
var basetime = new Date().getTime();
var c;
function setMaximalSize() {
browserSize = new BrowserSize();
c.width = viewX = browserSize.width;
c.height = viewY = browserSize.height;
}
function load() {
clearInterval(timer);
c = document.getElementById("c");
try {
gl = c.getContext("experimental-webgl", { depth : false });
} catch (e) {
}
if (!gl) {
alert("Your browser does not support WebGL");
return;
}
document.onmousemove = function(evt) {
mouseX = evt.pageX / viewX;
mouseY = 1 - evt.pageY / viewY;
};
document.onclick = function(evt) {
// halted = !halted;
};
window.onresize = setMaximalSize;
setMaximalSize();
c.width = viewX;
c.height = viewY;
prog_copy = gl.createProgram();
gl.attachShader(prog_copy, getShader(gl, "shader-vs"));
gl.attachShader(prog_copy, getShader(gl, "shader-fs-copy"));
gl.linkProgram(prog_copy);
prog_advance = gl.createProgram();
gl.attachShader(prog_advance, getShader(gl, "shader-vs"));
gl.attachShader(prog_advance, getShader(gl, "shader-fs-advance"));
gl.linkProgram(prog_advance);
prog_composite = gl.createProgram();
gl.attachShader(prog_composite, getShader(gl, "shader-vs"));
gl.attachShader(prog_composite, getShader(gl, "shader-fs-composite"));
gl.linkProgram(prog_composite);
prog_blur_horizontal = gl.createProgram();
gl.attachShader(prog_blur_horizontal, getShader(gl, "shader-vs"));
gl.attachShader(prog_blur_horizontal, getShader(gl, "shader-fs-blur-horizontal"));
gl.linkProgram(prog_blur_horizontal);
prog_blur_vertical = gl.createProgram();
gl.attachShader(prog_blur_vertical, getShader(gl, "shader-vs"));
gl.attachShader(prog_blur_vertical, getShader(gl, "shader-fs-blur-vertical"));
gl.linkProgram(prog_blur_vertical);
var posBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
var vertices = new Float32Array([ -1, -1, 0, 1, -1, 0, -1, 1, 0, 1, 1, 0 ]);
var aPosLoc = gl.getAttribLocation(prog_advance, "aPos");
gl.enableVertexAttribArray(aPosLoc);
var aTexLoc = gl.getAttribLocation(prog_advance, "aTexCoord");
gl.enableVertexAttribArray(aTexLoc);
var texCoords = new Float32Array([ 0, 0, 1, 0, 0, 1, 1, 1 ]);
var texCoordOffset = vertices.byteLength;
gl.bufferData(gl.ARRAY_BUFFER, texCoordOffset + texCoords.byteLength, gl.STATIC_DRAW);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, vertices);
gl.bufferSubData(gl.ARRAY_BUFFER, texCoordOffset, texCoords);
gl.vertexAttribPointer(aPosLoc, 3, gl.FLOAT, gl.FALSE, 0, 0);
gl.vertexAttribPointer(aTexLoc, 2, gl.FLOAT, gl.FALSE, 0, texCoordOffset);
var noisepixels = [];
var pixels = [];
for ( var i = 0; i < sizeX; i++) {
for ( var j = 0; j < sizeY; j++) {
noisepixels.push(Math.random() * 255, Math.random() * 255, Math.random() * 255, 255);
pixels.push(0, 0, 0, 255);
}
}
var pixels2 = [];
for ( var i = 0; i < sizeX / 2; i++) {
for ( var j = 0; j < sizeY / 2; j++) {
pixels2.push(0, 0, 0, 255);
}
}
var pixels3 = [];
for ( var i = 0; i < sizeX / 4; i++) {
for ( var j = 0; j < sizeY / 4; j++) {
pixels3.push(0, 0, 0, 255);
}
}
var pixels4 = [];
for ( var i = 0; i < sizeX / 8; i++) {
for ( var j = 0; j < sizeY / 8; j++) {
pixels4.push(0, 0, 0, 255);
}
}
var rawData = new Uint8Array(noisepixels);
texture_main_l = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_main_l);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX, sizeY, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(noisepixels);
texture_main_n = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_main_n);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX, sizeY, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
rawData = new Uint8Array(noisepixels);
texture_main2_l = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_main2_l);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX, sizeY, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(noisepixels);
texture_main2_n = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_main2_n);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX, sizeY, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
rawData = new Uint8Array(pixels);
texture_helper = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_helper);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX, sizeY, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(pixels2);
texture_helper2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_helper2);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX / 2, sizeY / 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(pixels3);
texture_helper3 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_helper3);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX / 4, sizeY / 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(pixels4);
texture_helper4 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_helper4);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX / 8, sizeY / 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(pixels);
texture_blur = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_blur);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX, sizeY, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(pixels2);
texture_blur2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_blur2);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX / 2, sizeY / 2, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(pixels3);
texture_blur3 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_blur3);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX / 4, sizeY / 4, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(pixels4);
texture_blur4 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_blur4);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX / 8, sizeY / 8, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
rawData = new Uint8Array(noisepixels);
texture_noise_l = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_noise_l);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX, sizeY, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
texture_noise_n = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture_noise_n);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, sizeX, sizeY, 0, gl.RGBA, gl.UNSIGNED_BYTE, rawData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
FBO_main = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_main);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_main_l, 0);
FBO_main2 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_main2);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_main2_l, 0);
FBO_helper = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_helper, 0);
FBO_helper2 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper2);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_helper2, 0);
FBO_helper3 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper3);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_helper3, 0);
FBO_helper4 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper4);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_helper4, 0);
FBO_blur = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_blur, 0);
FBO_blur2 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur2);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_blur2, 0);
FBO_blur3 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur3);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_blur3, 0);
FBO_blur4 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur4);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_blur4, 0);
FBO_noise = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_noise);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture_noise_l, 0);
gl.activeTexture(gl.TEXTURE2);
gl.bindTexture(gl.TEXTURE_2D, texture_blur);
gl.activeTexture(gl.TEXTURE3);
gl.bindTexture(gl.TEXTURE_2D, texture_blur2);
gl.activeTexture(gl.TEXTURE4);
gl.bindTexture(gl.TEXTURE_2D, texture_blur3);
gl.activeTexture(gl.TEXTURE5);
gl.bindTexture(gl.TEXTURE_2D, texture_blur4);
gl.activeTexture(gl.TEXTURE6);
gl.bindTexture(gl.TEXTURE_2D, texture_noise_l);
gl.activeTexture(gl.TEXTURE7);
gl.bindTexture(gl.TEXTURE_2D, texture_noise_n);
calculateBlurTexture();
posX1 = 0.5;
posY1 = 0.4;
scale1 = 1.23;
var w1 = 0;
sinW1 = Math.sin(w1);
cosW1 = Math.cos(w1);
posX2 = 0.5;
posY2 = 0.6;
scale2 = 2.5;
var w2 = 0.1;
w2 *= Math.PI;
sinW2 = Math.sin(w2);
cosW2 = Math.cos(w2);
timer = setInterval(fr, 500);
time = new Date().getTime();
animation = "animate";
anim();
}
var x1 = 0.5;
var y1 = 0.03;
var x2 = 0.5;
var y2 = 0.15;
var thickness = 1. / 0.01; // inverse actually, keeping the shader calculation low
var w1 = 0.2;
var w2 = 0.9;
var scale1 = 1.23;
var scale2 = 2.5;
function setUniforms(program) {
gl.uniform2f(gl.getUniformLocation(program, "pixelSize"), 1. / sizeX, 1. / sizeY);
gl.uniform4f(gl.getUniformLocation(program, "rnd"), Math.random(), Math.random(), Math.random(), Math.random());
gl.uniform1f(gl.getUniformLocation(program, "fps"), fps);
gl.uniform1f(gl.getUniformLocation(program, "time"), (new Date().getTime() - basetime) / 1000);
gl.uniform2f(gl.getUniformLocation(program, "aspect"), Math.max(1, viewX / viewY), Math.max(1, viewY / viewX));
gl.uniform2f(gl.getUniformLocation(program, "mouse"), mouseX, mouseY);
gl.uniform1i(gl.getUniformLocation(program, "sampler_prev"), 0);
gl.uniform1i(gl.getUniformLocation(program, "sampler_prev_n"), 1);
gl.uniform1i(gl.getUniformLocation(program, "sampler_blur"), 2);
gl.uniform1i(gl.getUniformLocation(program, "sampler_blur2"), 3);
gl.uniform1i(gl.getUniformLocation(program, "sampler_blur3"), 4);
gl.uniform1i(gl.getUniformLocation(program, "sampler_blur4"), 5);
gl.uniform1i(gl.getUniformLocation(program, "sampler_noise"), 6);
gl.uniform1i(gl.getUniformLocation(program, "sampler_noise_n"), 7);
gl.uniform1f(gl.getUniformLocation(program, "x1"), x1);
gl.uniform1f(gl.getUniformLocation(program, "y1"), y1);
gl.uniform1f(gl.getUniformLocation(program, "d1"), thickness);
gl.uniform1f(gl.getUniformLocation(program, "x2"), x2);
gl.uniform1f(gl.getUniformLocation(program, "y2"), y2);
gl.uniform1f(gl.getUniformLocation(program, "d2"), thickness * scale1);
gl.uniform1f(gl.getUniformLocation(program, "sin1"), Math.sin(w1));
gl.uniform1f(gl.getUniformLocation(program, "cos1"), Math.cos(w1));
gl.uniform1f(gl.getUniformLocation(program, "sin2"), Math.sin(w1 - w2));
gl.uniform1f(gl.getUniformLocation(program, "cos2"), Math.cos(w1 - w2));
gl.uniform1f(gl.getUniformLocation(program, "sin3"), Math.sin(w1 + w2));
gl.uniform1f(gl.getUniformLocation(program, "cos3"), Math.cos(w1 + w2));
gl.uniform1f(gl.getUniformLocation(program, "scale1"), scale1);
gl.uniform1f(gl.getUniformLocation(program, "scale2"), scale2);
}
function calculateBlurTexture() {
// simple blur
// horizontal
gl.viewport(0, 0, sizeX, sizeY);
gl.useProgram(prog_blur_horizontal);
gl.uniform2f(gl.getUniformLocation(prog_blur_horizontal, "pixelSize"), 1. / sizeX, 1. / sizeY);
gl.activeTexture(gl.TEXTURE0);
if (it < 0) {
gl.bindTexture(gl.TEXTURE_2D, texture_main2_l);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper);
} else {
gl.bindTexture(gl.TEXTURE_2D, texture_main_l);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper);
}
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// vertical
gl.viewport(0, 0, sizeX, sizeY);
gl.useProgram(prog_blur_vertical);
gl.uniform2f(gl.getUniformLocation(prog_blur_vertical, "pixelSize"), 1. / sizeX, 1. / sizeY);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_helper);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// double blur
// copy previous blur level to lower resolution texture
gl.viewport(0, 0, sizeX / 2, sizeY / 2);
gl.useProgram(prog_copy);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_blur);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur2);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// blur2 vertical
gl.viewport(0, 0, sizeX / 2, sizeY / 2);
gl.useProgram(prog_blur_vertical);
gl.uniform2f(gl.getUniformLocation(prog_blur_vertical, "pixelSize"), 2. / sizeX, 2. / sizeY);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_blur2);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper2);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// blur2 horizontal
gl.viewport(0, 0, sizeX / 2, sizeY / 2);
gl.useProgram(prog_blur_horizontal);
gl.uniform2f(gl.getUniformLocation(prog_blur_horizontal, "pixelSize"), 2. / sizeX, 2. / sizeY);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_helper2);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur2);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// blur3
// copy previous blur level to lower resolution texture
gl.viewport(0, 0, sizeX / 4, sizeY / 4);
gl.useProgram(prog_copy);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_blur2);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur3);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// blur3 vertical
gl.viewport(0, 0, sizeX / 4, sizeY / 4);
gl.useProgram(prog_blur_vertical);
gl.uniform2f(gl.getUniformLocation(prog_blur_vertical, "pixelSize"), 4. / sizeX, 4. / sizeY);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_blur3);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper3);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// blur3 horizontal
gl.viewport(0, 0, sizeX / 4, sizeY / 4);
gl.useProgram(prog_blur_horizontal);
gl.uniform2f(gl.getUniformLocation(prog_blur_horizontal, "pixelSize"), 4. / sizeX, 4. / sizeY);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_helper3);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur3);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// blur4
// copy previous blur level to lower resolution texture
gl.viewport(0, 0, sizeX / 8, sizeY / 8);
gl.useProgram(prog_copy);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_blur3);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur4);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// blur4 vertical
gl.viewport(0, 0, sizeX / 8, sizeY / 8);
gl.useProgram(prog_blur_vertical);
gl.uniform2f(gl.getUniformLocation(prog_blur_vertical, "pixelSize"), 8. / sizeX, 8. / sizeY);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_blur4);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_helper4);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
// blur4 horizontal
gl.viewport(0, 0, sizeX / 8, sizeY / 8);
gl.useProgram(prog_blur_horizontal);
gl.uniform2f(gl.getUniformLocation(prog_blur_horizontal, "pixelSize"), 8. / sizeX, 8. / sizeY);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_helper4);
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_blur4);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
}
function advance() {
x1 = 0.5;
thickness = (2 - mouseY * 1.) / 0.025;
y1 = 0.035;
x2 = 0.5 + (mouseX - 0.5) * 0.25;
y2 = 0.07 + mouseY * 0.14;
w1 = (0.5 - mouseX) * 0.15;
gl.viewport(0, 0, sizeX, sizeY);
gl.useProgram(prog_advance);
setUniforms(prog_advance);
if (it > 0) {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_main_l); // interpolated input
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texture_main_n); // "nearest" input
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_main2); // write to buffer
} else {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_main2_l); // interpolated
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texture_main2_n); // "nearest"
gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_main); // write to buffer
}
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
calculateBlurTexture();
it = -it;
}
function composite() {
gl.viewport(0, 0, viewX, viewY);
gl.useProgram(prog_composite);
setUniforms(prog_composite);
if (it < 0) {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_main_l);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texture_main_n);
} else {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture_main2_l);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, texture_main2_n);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
frames++;
}
function anim() {
if (!halted)
advance();
composite();
switch (animation) {
case "animate":
setTimeout("requestAnimFrame(anim)", delay);
break;
case "reset":
load();
break;
}
}
function setDelay(v) {
delay = parseInt(v);
}
function fr() {
var ti = new Date().getTime();
fps = Math.round(1000 * frames / (ti - time));
document.getElementById("fps").textContent = fps;
frames = 0;
time = ti;
}
</script>
<style type="text/css">
body {
background-color: #FFFFFF;
color: #000000;
}
a {
color: #666666;
text-decoration: none;
}
#c {
position: absolute;
top: 0;
left: 0;
z-index: -1;
}
#desc {
background-color: rgba(255, 255, 255, 0.2);
}
</style>
</head>
<body onload="load()">
<div id="desc">
<b><i>Progressive <a href="http://en.wikipedia.org/wiki/L-system" target=new>Lindenmayer</a> tree fractal</i> </b><br />
Fps: <span id="fps"></span>
</div>
<canvas id="c"></canvas>
</body>
</html>
@jbilcke
Copy link

jbilcke commented Oct 6, 2011

Nice!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment