Created
April 20, 2016 14:53
-
-
Save ikr7/6a2b153cf3f907ee7b483929047d18b6 to your computer and use it in GitHub Desktop.
WebGL でマンデルブロくん
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> | |
<div>左/右クリックでその辺りにズームイン/アウトするよ WebGL サポートのある新しいめのブラウザで見てね!</div> | |
<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 = 512; | |
float mand (vec2 p) { | |
vec2 z = vec2(0, 0); | |
vec2 z1 = vec2(0, 0); | |
for (int n = 0; n < MAX; n++) { | |
z1.x = pow(z.x, 2.0) - pow(z.y, 2.0); | |
z1.y = z.x * z.y * 2.0; | |
z1 -= p; | |
if (length(z1.xy) > 2.0) { | |
return float(n) / float(MAX); | |
} | |
z = z1; | |
} | |
return 0.0; | |
} | |
void main(void) { | |
vec2 pos = gl_FragCoord.xy * (view_size.xy / res.xy) + view_pos.xy - view_size.xy / 2.0; | |
float b = mand(pos); | |
gl_FragColor = vec4(b, b, b, 1); | |
} | |
</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 = 4; | |
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; | |
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 + 400, H / 2, true); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment