UNPKG

4.57 kBMarkdownView Raw
1## Mandelbrot, ThreeJS, WebGL
2
3**Requires WebGL be enabled in your browser.**
4
5This is a one-pint demo of how ThreeJS and Smartdown can be used to understand the [Mandelbrot Set](https://en.wikipedia.org/wiki/Mandelbrot_set). Although Smartdown is not intended to be a programming language to build *apps* with, it is perfect for *Explorable Explanations* such as this Mandelbrot Explorer.
6
7*This is a draft. I want to add more prose and more parametrization.*
8
9---
10
11[Zoom Out](:=zoom=zoom/2.0) [Zoom In](:=zoom=zoom*2.0) [Up](:=posY=posY+0.1/zoom) [Down](:=posY=posY-0.1/zoom) [Left](:=posX=posX-0.1/zoom) [Right](:=posX=posX+0.1/zoom) **AutoZoom** [](:Xbounciness)
12
13[Entire Set](:=posX=0.6;posY=0.0;zoom=1) [Region A](:=posX=0.570;posY=0.630;zoom=25) [Region B](:=posX=0.190;posY=0.650;zoom=50) [Region C](:=posX=0.04292602539062498;posY=0.6965332031250012;zoom=2048)
14[Set X/Y/Zoom](:=useCoordinates=1) [](:?coordinates)
15
16```javascript/playable/autoplay
17var vertexShader =
18`
19precision highp float;
20uniform float zoom;
21varying vec2 pos;
22
23void main () {
24 pos = position.xy / zoom;
25 gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
26}
27`;
28
29var fragmentShader =
30`
31precision highp float;
32uniform float zoom;
33varying vec2 pos;
34uniform float posX;
35uniform float posY;
36
37void main () {
38 vec2 basePos = vec2(pos.x - posX, pos.y - posY);
39 vec2 fractal = basePos;
40 int iterations = 20 + int(zoom);
41
42 for (int i = 0; i < 1000; i++) {
43 if (i > iterations) {
44 break;
45 }
46 fractal = basePos + vec2(
47 fractal.x * fractal.x - fractal.y * fractal.y,
48 2.0 * fractal.x * fractal.y
49 );
50 }
51
52 // interpolate fractal color over position
53 float x = abs(fractal.x);
54 float y = abs(fractal.y);
55 float z = (x + y);
56 float magnitude = length(fractal);
57 x = 2.0 * magnitude * x;
58 y = 2.0 * magnitude * y;
59 if (x > 1.0) {
60 x = 1.0;
61 }
62 if (y > 1.0) {
63 y = 1.0;
64 }
65 if (z > 1.0) {
66 z = 1.0;
67 }
68 gl_FragColor = vec4(x, y, z, 1.0);
69}
70`;
71
72var that = this;
73var myDiv = that.div;
74myDiv.style.background = 'darkslateblue';
75myDiv.style['vertical-align'] = 'center';
76myDiv.style['text-align'] = 'center';
77myDiv.style['padding'] = '5px';
78var width = 450.0;
79var height = 350.0;
80
81smartdown.setVariable('posX', 0.6, 'number');
82smartdown.setVariable('posY', 0.0, 'number');
83smartdown.setVariable('zoom', 0.666, 'number');
84myDiv.innerHTML = '';
85var scene = new THREE.Scene();
86var camera = new THREE.PerspectiveCamera(75.0, width / height, 0.1, 1000.0);
87camera.position.z = 1;
88
89// create canvas
90var renderer = new THREE.WebGLRenderer();
91renderer.setSize(width, height);
92myDiv.appendChild(renderer.domElement);
93
94// create mandelbrot mesh
95var geometry = new THREE.PlaneGeometry(2.0, 2.0, 0.0);
96var material = new THREE.ShaderMaterial({
97 uniforms: {
98 zoom: { type: 'f', value: that.env.zoom },
99 posX: { type: 'f', value: that.env.posX },
100 posY: { type: 'f', value: that.env.posY }
101 },
102 vertexShader: vertexShader,
103 fragmentShader: fragmentShader
104});
105
106var mesh = new THREE.Mesh(geometry, material);
107scene.add(mesh);
108
109var zoomOld = null;
110var posXOld = null;
111var posYOld = null;
112var bouncinessOld = null;
113var coordinatesOld = null;
114
115function render(delta) {
116 var posX = that.env.posX;
117 var posY = that.env.posY;
118 var zoom = that.env.zoom;
119 var bounciness = that.env.bounciness;
120 var coordinates = that.env.coordinates;
121 var coordinatesNew = `${posX}/${posY}/${zoom}`;
122 var useCoordinates = that.env.useCoordinates;
123
124 if (delta) {
125 if (useCoordinates) {
126 var coordinatesParts = coordinates.split('/');
127 posX = Number(coordinatesParts[0]);
128 posY = Number(coordinatesParts[1]);
129 zoom = Number(coordinatesParts[2]);
130 coordinatesNew = coordinates;
131 that.env.useCoordinates = 0;
132 that.env.posX = posX;
133 that.env.posY = posY;
134 that.env.zoom = zoom;
135 }
136
137 if (bounciness || bouncinessOld ||
138 zoom !== zoomOld ||
139 posX !== posXOld ||
140 posY !== posYOld) {
141 zoomOld = zoom;
142 posXOld = posX;
143 posYOld = posY;
144 bouncinessOld = bounciness;
145 coordinatesOld = coordinatesNew;
146 smartdown.setVariable('coordinates', coordinatesNew);
147 var bounce = bounciness ? (1.25 + Math.cos(delta / 2500)) : 1;
148 mesh.material.uniforms.zoom.value = zoom * bounce;
149 mesh.material.uniforms.posX.value = posX;
150 mesh.material.uniforms.posY.value = posY;
151 renderer.render(scene, camera);
152 }
153 requestAnimationFrame(render);
154 }
155 else {
156 requestAnimationFrame(render);
157 }
158}
159
160render();
161```
162
163---
164
165[Back to Home](:@Home)
166