|
<!DOCTYPE html> |
|
<body style="margin: 0; overflow: hidden;"> |
|
<script type="vs"> |
|
void main(void) { |
|
float x = float((gl_VertexID & 1) << 2); |
|
float y = float((gl_VertexID & 2) << 1); |
|
gl_Position = vec4(x - 1., y - 1., 0, 1); |
|
} |
|
</script> |
|
<script type="fs"> |
|
precision highp float; |
|
uniform vec4 mr; |
|
out vec4 o; |
|
void main(void) { |
|
vec2 p = gl_FragCoord.xy; |
|
vec2 q = 5.*(p + p - mr.ba) / mr.ba; |
|
for(; o.a++ < 33.;) { |
|
q = abs(q) / dot(q, q) - mr.xy / mr.b; |
|
o += length(q) / 2e2; |
|
} |
|
} |
|
</script> |
|
<script> |
|
var canvas = document.body.appendChild(document.createElement('canvas')); |
|
var ctx = canvas.getContext('webgl2'); |
|
ctx.viewport(0, 0, canvas.width = innerWidth, canvas.height = innerHeight); |
|
|
|
var p = program(ctx, 0, 1); |
|
var mr = p.uniform('4f', 'mr'); |
|
p.use(); |
|
|
|
addEventListener('mousemove', function (e) { |
|
mr(e.x, canvas.height - e.y, canvas.width, canvas.height); |
|
ctx.drawArrays(ctx.TRIANGLE_FAN, 0, 3); |
|
}); |
|
|
|
function program(gl, v, f) { |
|
var p = gl.createProgram(); |
|
shader(v, gl.VERTEX_SHADER); |
|
shader(f, gl.FRAGMENT_SHADER); |
|
gl.linkProgram(p); |
|
return { |
|
uniform: function (type, name) { |
|
var u = gl.getUniformLocation(p, name); |
|
return function (v1, v2, v3, v4) { |
|
gl['uniform' + type](u, v1, v2, v3, v4); |
|
} |
|
}, |
|
use: function () { |
|
gl.useProgram(p); |
|
} |
|
}; |
|
|
|
function shader(i, type) { |
|
var s = gl.createShader(type); |
|
gl.shaderSource(s, "#version 300 es\n" + document.scripts[i].innerText); |
|
gl.compileShader(s); |
|
gl.attachShader(p, s); |
|
} |
|
} |
|
</script> |
|
</body> |