mirror of
https://github.com/gpujs/gpu.js.git
synced 2025-12-08 20:35:56 +00:00
...it kind of snowballed from some needs Fixes #521 - If `tactic` is not set, check precision allowed from WebGL, and automatically change based off needs, otherwise use value from `tactic`. Fixes #535 - Internally check if texture from argument is the same as output, if so, clone this texture, and then clean it up after the kernel runs. Fixes #536 - Normalize all declarations to non-destructured, and then parse Fixes #537 - Change logic Fixes #538 - Found the GL script that would work, and reduced the methods to use it Fixes #539 - Found a better way of testing random, and this gives me an error for 1 in 10 runs, acceptable Some refactoring for less duplicate code and documentation
124 lines
3.1 KiB
HTML
124 lines
3.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<script src="../dist/gpu-browser.min.js"></script>
|
|
<style>
|
|
body {
|
|
text-align: center;
|
|
margin: 0;
|
|
}
|
|
canvas {
|
|
padding: 0;
|
|
margin: 0;
|
|
}
|
|
div {
|
|
position: absolute;
|
|
color: white;
|
|
margin-left: auto;
|
|
margin-right: auto;
|
|
left: 0;
|
|
right: 0;
|
|
}
|
|
</style>
|
|
<body>
|
|
<div>Left click to zoom in, right click to zoom out.</div>
|
|
</body>
|
|
<script>
|
|
function f(x, c) {
|
|
return [
|
|
(x[0] * x[0]) - (x[1] * x[1]) + c[0],
|
|
(x[0] * x[1]) + (x[0] * x[1]) + c[1],
|
|
];
|
|
}
|
|
|
|
function palette(t, a, b, c, d) {
|
|
return [
|
|
a[0] + b[0] * Math.cos(6.28318 * (c[0] * t + d[0])),
|
|
a[1] + b[1] * Math.cos(6.28318 * (c[1] * t + d[1])),
|
|
a[2] + b[2] * Math.cos(6.28318 * (c[2] * t + d[2]))
|
|
];
|
|
}
|
|
|
|
function vectorLength(vector) {
|
|
return Math.sqrt(vector[0]*vector[0]+vector[1]*vector[1]);
|
|
}
|
|
|
|
const gpu = new GPU();
|
|
|
|
gpu
|
|
.addFunction(f)
|
|
.addFunction(palette)
|
|
.addFunction(vectorLength);
|
|
|
|
const calculateMandelbrotSet = gpu.createKernel(function(zoomCenter, zoomSize, maxIterations) {
|
|
let x = [0, 0];
|
|
let c = [
|
|
zoomCenter[0] + ((this.thread.x / this.output.x) * 4 - 2) * (zoomSize / 4),
|
|
zoomCenter[1] + ((this.thread.y / this.output.y) * 4 - 2) * (zoomSize / 4)
|
|
];
|
|
let escaped = false;
|
|
let iterations = 0;
|
|
for (let i = 0; i < maxIterations; i++) {
|
|
iterations = i;
|
|
x = f(x, c);
|
|
if (vectorLength(x) > 2) {
|
|
escaped = true;
|
|
break;
|
|
}
|
|
}
|
|
if (escaped) {
|
|
const pixel = palette(iterations / maxIterations, [0, 0, 0], [.59, .55, .75], [.1, .2, .3], [.75, .75, .75]);
|
|
this.color(pixel[0], pixel[1], pixel[2], 1);
|
|
} else {
|
|
this.color(.85, .99, 1, 1);
|
|
}
|
|
})
|
|
.setGraphical(true)
|
|
.setOutput([800, 800]);
|
|
|
|
let targetZoomCenter = [0, 0],
|
|
zoomFactor = 1,
|
|
zoomCenter = [0, 0],
|
|
zoomSize = 4,
|
|
maxIterations = 500,
|
|
stopZooming = true;
|
|
|
|
calculateMandelbrotSet(zoomCenter, zoomSize, maxIterations);
|
|
const canvas = calculateMandelbrotSet.canvas;
|
|
document.body.appendChild(canvas);
|
|
|
|
canvas.onmousedown = (e) => {
|
|
let x = e.offsetX / canvas.width,
|
|
y = e.offsetY / canvas.height;
|
|
targetZoomCenter[0] = zoomCenter[0] - zoomSize / 2.0 + x * zoomSize;
|
|
targetZoomCenter[1] = zoomCenter[1] + zoomSize / 2.0 - y * zoomSize;
|
|
stopZooming = false;
|
|
zoomFactor = e.buttons & 1 ? 0.99 : 1.01;
|
|
render();
|
|
return true;
|
|
};
|
|
canvas.oncontextmenu = () => { return false; };
|
|
canvas.onmouseup = () => { stopZooming = true; };
|
|
|
|
function render() {
|
|
calculateMandelbrotSet(zoomCenter, zoomSize, maxIterations);
|
|
if (!stopZooming) {
|
|
maxIterations -= 10;
|
|
if (maxIterations < 50) {
|
|
maxIterations = 50;
|
|
}
|
|
|
|
zoomSize *= zoomFactor;
|
|
|
|
zoomCenter[0] += 0.1 * (targetZoomCenter[0] - zoomCenter[0]);
|
|
zoomCenter[1] += 0.1 * ( targetZoomCenter[1] - zoomCenter[1]);
|
|
|
|
window.requestAnimationFrame(render);
|
|
} else if (maxIterations < 500) {
|
|
maxIterations += 10;
|
|
window.requestAnimationFrame(render);
|
|
}
|
|
}
|
|
window.requestAnimationFrame(render);
|
|
</script>
|
|
</html>
|