Fractal WebGL

by Vladimir

HTML

<canvas width="600" height="600" id="canvas"/>

<script type="glsl/vertex">

attribute vec2 coords;

void main(void) {
  gl_Position = vec4(coords.xy, 0.0, 1.0);
}

</script>

<script type="glsl/fragment">

precision highp float;

uniform vec2 mouse;
uniform vec2 resolution;

void main(void) {

    vec2 m = mouse/resolution;
    vec2 p = gl_FragCoord.xy;
    
    // вот собственно сама формула реализована в этих 3 строчках
    vec2 q = (p + p - resolution) / resolution.y;
    for(int i = 0; i < 10; i++)
         q = abs(q)/dot(q,q) -  m;
         
         
    gl_FragColor = vec4(q, q.x/q.y, 1.0);
}

</script>

JavaScript

let gl = canvas.getContext('webgl');

gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,  3, -1, -1, 3, -1]), gl.STATIC_DRAW);

let pid = gl.createProgram();
shader('vertex', gl.VERTEX_SHADER);
shader('fragment', gl.FRAGMENT_SHADER);
gl.linkProgram(pid);
gl.useProgram(pid);

let coords = gl.getAttribLocation(pid, "coords");
gl.vertexAttribPointer(coords, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(coords);

let mouse = gl.getUniformLocation(pid, 'mouse');
let resolution = gl.getUniformLocation(pid, 'resolution');
gl.uniform2f(resolution, gl.drawingBufferWidth, gl.drawingBufferHeight);

let changeCenter = e => {
  e = e.touches ? e.touches[0] : e;
  gl.uniform2f(mouse, e.pageX - canvas.offsetLeft, e.pageY - canvas.offsetTop);
  draw();
}

window.addEventListener('mousemove', changeCenter);
window.addEventListener('touchmove', changeCenter);

draw();

function draw() {
  gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
  gl.clearColor(0, 0, 0, 0);
  gl.drawArrays(gl.TRIANGLES, 0, 3);
}

function shader(src, type) {
  let sid = gl.createShader(type);
  gl.shaderSource(sid, document.querySelector(`script[type="glsl/${src}"]`).textContent);
  gl.compileShader(sid);
  var message = gl.getShaderInfoLog(sid);
  gl.attachShader(pid, sid);
  if (message.length > 0) {
    console.log(src.split('\n').map(function (str, i) {
      return ("" + (1 + i)).padStart(4, "0") + ": " + str
    }).join('\n'));
    throw message;
  }
}