Created
October 2, 2016 11:31
-
-
Save ikr7/75c2cb5a0ecc8dfee849594c7464581f to your computer and use it in GitHub Desktop.
WebGL でマンデルブロくん with Distance Estimation
This file contains 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> | |
<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