Skip to content

Instantly share code, notes, and snippets.

@ikr7
Created October 2, 2016 11:31
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 ikr7/75c2cb5a0ecc8dfee849594c7464581f to your computer and use it in GitHub Desktop.
Save ikr7/75c2cb5a0ecc8dfee849594c7464581f to your computer and use it in GitHub Desktop.
WebGL でマンデルブロくん with Distance Estimation
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebGL でマンデルブロくん</title>
<style>
body {
margin:0;
overflow:hidden
}
div {
position: fixed;
width: 100%;
background: rgba(255, 255, 255, 0.2);
color: white;
}
</style>
</head>
<body>
<canvas></canvas>
<script id="fs" type="x-shader/x-fragment">
precision highp float;
uniform vec2 res;
uniform vec2 view_pos;
uniform vec2 view_size;
const int MAX = 255;
float DE (vec2 c) {
vec2 z = vec2(0.0, 0.0);
vec2 dz = vec2(0.0, 0.0);
float m2 = 0.0;
for (int i = 0; i < MAX; i++) {
if(m2 > 1024.0) continue;
dz = 2.0 * vec2(z.x * dz.x - z.y * dz.y + 1.0, z.x * dz.y + z.y * dz.x);
z = vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y) + c;
m2 = dot(z, z);
}
return 0.5 * sqrt(dot(z, z) / dot(dz, dz)) * log(dot(z, z));
}
void main(void) {
vec2 pos = gl_FragCoord.xy * (view_size.xy / res.xy) + view_pos.xy - view_size.xy / 2.0;
float d = DE(pos);
d = clamp(8.0 * d / view_size.x, 0.0, 1.0);
d = pow(d, 0.25);
gl_FragColor = vec4(
d,
d,
d,
1.0
);
}
</script>
<script>
var canvas = document.querySelector('canvas');
var W = Math.max(
document.body.clientWidth,
document.body.scrollWidth,
document.documentElement.scrollWidth,
document.documentElement.clientWidth
);
var H = Math.max(
document.body.clientHeight,
document.body.scrollHeight,
document.documentElement.scrollHeight,
document.documentElement.clientHeight
);
canvas.width = W;
canvas.height = H;
var gl = canvas.getContext('experimental-webgl', { preserveDrawingBuffer: true });
var vShaderSource = 'attribute vec2 a_position;void main(){gl_Position = vec4(a_position, 1.0, 1.0);}';
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vShaderSource);
gl.compileShader(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, document.getElementById('fs').textContent);
gl.compileShader(fragmentShader);
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0]), gl.STATIC_DRAW);
var a_position = gl.getAttribLocation(program, 'a_position');
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_position);
var res = gl.getUniformLocation(program, 'res');
var view_pos = gl.getUniformLocation(program, 'view_pos');
var view_size = gl.getUniformLocation(program, 'view_size');
var z = 10;
var view_w;
var view_h;
var view_x = 0;
var view_y = 0;
var update = function (clickX, clickY, zin) {
clickY = H - clickY;
if (zin) {
z *= (7 / 10);
} else {
z *= (10 / 7);
}
view_w = z;
view_h = z * (H / W);
view_x = view_x + clickX * (view_w / W) - view_w / 2;
view_y = view_y + clickY * (view_h / H) - view_h / 2;
console.log(view_x, view_y, view_w, view_h);
gl.uniform2fv(res, new Float32Array([
W,
H
]));
gl.uniform2fv(view_pos, new Float32Array([
view_x,
view_y
]));
gl.uniform2fv(view_size, new Float32Array([
view_w,
view_h
]));
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
};
canvas.addEventListener('click', function (e) {
var x = e.clientX;
var y = e.clientY;
update(x, y, true);
});
canvas.addEventListener('contextmenu', function (e) {
e.preventDefault();
var x = e.clientX;
var y = e.clientY;
update(x, y, false);
});
update(W / 2, H / 2, true);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment