Created
October 5, 2011 22:14
-
-
Save philogb/1265902 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice!