-
Notifications
You must be signed in to change notification settings - Fork 1
/
3D-fractals.html
383 lines (359 loc) · 25.7 KB
/
3D-fractals.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
<!DOCTYPE html>
<html lang="es">
<head>
<title>Fractales 3D</title>
<!-- Código para la visualización de fractales -->
<script type="module" src="static/js/fractals-3D.js"></script>
<!-- jQuery -->
<script type="text/javascript" src="static/js/jquery-3.6.0.min.js"></script>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script>
<!-- Botones para RRSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- MathJax para las expresiones matemáticas -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<!-- CSS propio -->
<link rel="stylesheet" href="static/css/hover-style.css">
<!-- Meta -->
<meta charset="UTF-8">
<meta name="application-name" content="Visualización de fractales">
<meta name="author" content="Juan Antonio Villegas Recio">
<meta name="description" content="Visualización de fractales en 3 dimensiones">
<link rel="icon" href="static/img/logo.png">
</head>
<body>
<!--
-- ─── CABECERA ────────────────────────────────────────────────────
-->
<header class="row d-flex flex-wrap justify-content-around py-3 mb-4 border-bottom w-100 p-3">
<a href="index.html" class="d-flex align-items-center justify-content-center mb-3 mb-md-0 me-md-auto text-dark text-decoration-none col-xl-6">
<img src="static/img/logo.png" id="logo">
<span class="fs-4"><h1>Visualización de Fractales 3D</h1></span>
</a>
<ul class="nav nav-pills col-xl-6 justify-content-center">
<li class="nav-item"><a href="./index.html"><button class="btn-change">Home</button></a></li>
<li class="nav-item"><a href="./2D-fractals.html"><button class="btn-change">Fractales 2D</button></a></li>
<li class="nav-item"><a href="./3D-fractals.html"><button class="btn-change">Fractales 3D</button></a></li>
</ul>
</header>
<!--
-- ─── CONTENIDO ───────────────────────────────────────────────────
-->
<main class="container-xl">
<section class="row">
<!-- WEBGL CANVAS -->
<div class="col-lg-8" id="canvas-wapper">
<canvas class="container-fluid" id="glCanvas" width="1280" height="720"></canvas>
<div class="row justify-content-center">
<span class="col-4 fs-5 text">Modo de uso</span>
<div class="col-3 form-check">
<input class="form-check-input" type="radio" name="modo" id="interactivo" value="0">
<label class="form-check-label" for="interactivo">
Modo interactivo
</label>
</div>
<div class="col-3 form-check">
<input class="form-check-input" type="radio" name="modo" id="a-demanda" value="1" checked>
<label class="form-check-label" for="a-demanda">
Modo a demanda
</label>
</div>
</div>
<div class="row justify-content-around">
<button type="button" class="col-4 btn-change" id="botonReset">Reset</button>
<button class="col-4 btn-change" id="redraw">Redibujar</button>
</div>
</div>
<!-- PANEL DE CONTROL -->
<aside class="col-lg-4">
<div class="accordion accordion-flush" id="accordionFlushExample">
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
<span class="fs-5 text">Parámetros del fractal</span>
</button>
</h2>
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
<div class="accordion-body">
<div class="row">
<b class="col-7">¿Qué fractal quieres ver?</b>
<div class="col-5">
<select class="form-select form-select-sm mb-3" aria-label=".form-select-lg example" id="fractales">
<option value="1" selected>Mandelbub</option>
<option value="2">Julia</option>
<option value="3">Mandelbrot</option>
</select>
</div>
</div>
<section id="constanteJulia">
<b>Constante del Conjunto de Julia</b><br> \(c = i\cdot x + j\cdot y + k\cdot z + w \)
<div class="container" id="deslizadorJuliaX">
<div class="row align-items-center justify-content-between">
<b class="col-2">x:</b>
<input class="col-5" id="juliaX" type="range" min="-2" max="2" step="0.01">
<input type="number" class="col-3" id="valorJuliaX" min="-2" max="2" step="0.01"></input>
</div>
</div>
<div class="container" id="deslizadorJuliaY">
<div class="row align-items-center justify-content-between">
<b class="col-2">y:</b>
<input class="col-5" id="juliaY" type="range" min="-2" max="2" step="0.01">
<input type="number" class="col-3" id="valorJuliaY" min="-2" max="2" step="0.01"></input>
</div>
</div>
<div class="container" id="deslizadorJuliaZ">
<div class="row align-items-center justify-content-between">
<b class="col-2">z:</b>
<input class="col-5" id="juliaZ" type="range" min="-2" max="2" step="0.01">
<input type="number" class="col-3" id="valorJuliaZ" min="-2" max="2" step="0.01"></input>
</div>
</div>
<div class="container" id="deslizadorJuliaW">
<div class="row align-items-center justify-content-between">
<b class="col-2">w:</b>
<input class="col-5" id="juliaW" type="range" min="-2" max="2" step="0.01">
<input type="number" class="col-3" id="valorJuliaW" min="-2" max="2" step="0.01"></input>
</div>
</div>
</section>
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="flush-headingTwo">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseTwo" aria-expanded="false" aria-controls="flush-collapseTwo">
<span class="fs-5 text">Ray-Tracing</span>
</button>
</h2>
<div id="flush-collapseTwo" class="accordion-collapse collapse" aria-labelledby="flush-headingTwo" >
<div class="accordion-body">
<h5>Posición actual (coordenadas cartesianas)</h5>
<div class="row justify-content-around align-items-center">
<div class="col-4 text-center"><b>x</b></div>
<div class="col-4 text-center"><b>y</b></div>
<div class="col-4 text-center"><b>z</b></div>
</div>
<div class="row justify-content-around align-items-center">
<input class="col-3" id="posX" type="number" min="-100" max="100" step="0.1">
<input class="col-3" id="posY" type="number" min="-100" max="100" step="0.1">
<input class="col-3" id="posZ" type="number" min="-100" max="100" step="0.1">
</div><br>
<h5>Epsilon</h5>
<div class="container" id="epsilon">
<div class="row align-items-center justify-content-between">
<b class="col-2">\(\varepsilon\):</b>
<input class="col-5" id="current_epsilon" type="range" min="1" max="4" step="1">
<div class="col-3" id="valor_epsilon"></div>
</div>
</div><br>
<h5>Supersampling Antialiasing</h5>
<div class="form-check form-switch" style="padding-left: 5.5em;">
<input class="form-check-input" type="checkbox" id="antialiasing">
<label class="form-check-label" for="antialiasing">Activar/desactivar SSAA</label>
</div>
<div class="container" id="deslizadorNSamples">
<div class="row align-items-center justify-content-between">
<b class="col-5">Rayos por píxel:</b>
<input class="col-5" id="nSamples" type="range" min="1" max="4" step="1">
<div class="col-2" id="valorNSamples"></div>
</div>
</div>
</div>
</div>
</div>
<div class="accordion-item">
<h4 class="accordion-header" id="flush-headingThree">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#flush-collapseThree" aria-expanded="false" aria-controls="flush-collapseThree">
<span class="fs-5 text">Modelo de iluminación</span>
</button>
</h4>
<div id="flush-collapseThree" class="accordion-collapse collapse" aria-labelledby="flush-headingThree" >
<div class="accordion-body">
<h5>Propiedades del material</h5>
<div class="row justify-content-center">
<input id="ka" type="color" class="col-2 form-control form-control-color" title="Elige un color para la intensidad ambiental">
<label for="ka" class="col-8 form-label">Componente ambiental</label>
</div>
<div class="row justify-content-center">
<input id="kd" type="color" class="col-2 form-control form-control-color" title="Elige un color para la intensidad difusa">
<label for="kd" class="col-8 form-label">Componente difusa</label>
</div>
<div class="row justify-content-center">
<input id="ks" type="color" class="col-2 form-control form-control-color" title="Elige un color para la intensidad especular">
<label for="ks" class="col-8 form-label">Componente especular</label>
</div>
<div class="container" id="shiness">
<div class="row align-items-center justify-content-between">
<b class="col-2">Brillo:</b>
<input class="col-5" id="sh" type="range" min="10.0" max="1000" step="5">
<input type="number" class="col-3" id="valor_sh" min="1.0" max="1000" step="1"></input>
</div>
</div>
<h5>Luz izquierda</h5>
<div class="row justify-content-center">
<input id="lightColor0" type="color" class="col-2 form-control form-control-color" title="Elige un color para la luz izquierda">
<label for="lightColor0" class="col-8 form-label">Color de la luz</label>
</div>
<div class="row justify-content-center align-items-center">
<input class="col-1" type="checkbox" value="" id="shadows_0">
<label class="col-8" for="shadows_0">
Sombras arrojadas
</label>
</div>
<h5>Luz derecha</h5>
<div class="row justify-content-center">
<input id="lightColor1" type="color" class="col-2 form-control form-control-color" title="Elige un color para la luz derecha">
<label for="lightColor1" class="col-8 form-label">Color de la luz</label>
</div>
<div class="row justify-content-center align-items-center">
<input class="col-1" type="checkbox" value="" id="shadows_1">
<label class="col-8" for="shadows_1">
Sombras arrojadas
</label>
</div>
</div>
</div>
</div>
<br>
<span id="contador-valor" class="fs-5 text"></span><br>
</aside>
</section>
<!-- AYUDA -->
<section class="container">
<h2>Controles:</h2>
<ul>
<li>Teclas +/-: Ampliar o reducir el zoom</li>
<li>Flechas: Desplazarse por el espacio</li>
</ul>
<h2>Ayuda</h2>
<p>
En los siguientes párrafos se explica de forma intuitiva el significado y el efecto provocado por cada uno de los parámetros modificables. Previamente, explicamos algunas nociones sobre los algoritmos utilizados para visualizar estas escenas.
</p>
<p>
El algoritmo utilizado para graficar una escena 3D es 'Ray-Tracing', el cual consiste en imaginar la escena que queremos visualizar, que en este caso está compuesta por un plano con textura de tablero de ajedrez y un fractal 3D, y desde una posición que tomamos como punto de vista posicionar un plano el cual identificamos con la pantalla y dividimos en píxeles (este plano se denomina 'plano de proyección'). Posteriormente, se 'trazan rayos' hacia la escena, uno por cada píxel. En caso de intersección con algún objeto, se colorea el píxel del color asociado a la intersección.
</p>
<img class="w-50 p-3 mx-auto d-block" src="static/img/RT.png">
<p>
La manera de calcular esta intersección es mediante el algoritmo conocido como 'Sphere-Tracing'. Este consiste en avanzar poco a poco a lo largo del rayo mediante estimaciones de la distancia a los objetos que componen la escena, hasta detectar que un punto del rayo se encuentra a una distancia muy pequeña del objeto, en cuyo caso decidiremos que hemos encontrado la intersección.
</p>
<p>
Veamos ahora el significado de cada parámetro.
</p>
<h3>Modo de uso</h3>
<p>
Esta página se puede usar de dos maneras debido al alto coste computacional que requiere aplicar 'sphere-tracing':
</p>
<ul>
<li><strong>Modo interactivo</strong> : La escena cambia conforme cambia cada parámetro. Es la opción más ilustrativa y en la que más se aprecian los cambios en los distintos parámetros, pero también la más costosa. No recomendamos usar este modo, o al menos no abusar de él con parámetros exigentes si el computador es antiguo o tiene una mala GPU.</li>
<li><strong>Modo a demanda</strong>: En este caso la escena no cambia al modificar los parámetros, aunque si cambian internamente. Una vez se han ajustado a nuestro gusto, se pulsa el botón <a class="text-primary" href="#redraw">Redibujar</a> para que se grafique la escena con los nuevos parámetros.</li>
</ul>
<h3>Botón 'Reset'</h3>
<p>
Al pulsarlo se restablecen los parámetros a los iniciales, es decir, los que había al cargar la página por primera vez.
</p>
<h3>Botón 'Redibujar'</h3>
<p>
Al pulsarlo se dibuja la escena con los valores que tengan los parámetros en el momento que se pulsa. Cada vez que se redibuja la escena, sea por este botón o porque esté activo el modo interactivo, se actualiza el 'tiempo de procesado', que especifica el tiempo en milisegundos que tarda en procesarse el frame.
</p>
<p>
En general, se recomienda usar los parámetros estándar y el modo interactivo para moverse por la escena, y en el momento que se desee primar el realismo y la calidad de la imagen activar el modo a demanda, especificar parámetros concretos más exigentes y redibujar.
</p>
<h3>Parámetros del fractal</h3>
<p>
En la página de <a href="2D-fractals.html#ayuda2D" class="text-primary">fractales 2D</a> se explica la metodología para graficar conjuntos de Julia y Mandelbrot mediante iteración de números complejos. Para dar el salto a 3 dimensiones se utiliza una generalización de los complejos: los cuaternios, los cuales pueden identificarse con \(\mathbb R^4\), de forma que aquí representamos una proyección de los conjuntos de Julia y Mandelbrot 4-dimensionales en 3 dimensiones.
</p>
<p>
Se ofrece la posibilidad de elegir entre la visualización de los conjuntos de Julia y Mandelbrot fijando esta vez para los conjuntos de Julia una constante \(c=ix + jy + kz + w\), es decir, un cuaternio, 4 parámetros de libertad. También es posible visualizar el conjunto de Mandelbub, que es una generalización 3D del conjunto de Mandelbrot de orden 8, bastante más visual que el conjunto de Mandelbrot generalizado.
</p>
<p>
Recomendamos seleccionar la opción de visualizar conjuntos de Julia y modificar los parámetros de la constante \(c\), o abrir la página de <a href="2D-fractals.html" class="text-primary">fractales 2D</a> y comparar el conjunto de Mandelbrot 2D con el 3D y el conjunto de Mandelbrot con exponente \(m=8\) con el conjunto de Mandelbub.
</p>
<h3>Ray-Tracing</h3>
<p>
En este apartado se eligen parámetros que se relacionan directamente con el algoritmo utilizado para la visualización de la escena, no tanto con el fractal. Dividimos la sección en tres subapartados:
</p>
<h4>Posición actual (coordenadas cartesianas)</h4>
<p>
La escena está dotada de una cámara orbital que se mueve mirando siempre de forma fija al punto \((0,0,0)\), que es donde están fijados todos los fractales. Así, cada vez que se pulsan las flechas o las teclas '+/-' el movimiento se hace en la cámara orbital y en torno al punto origen. En este conjunto de parámetros se especifican las coordenadas cartesianas del punto en el cual se sitúa el observador en cada momento, pudiendo modificar la posición a nuestro gusto, pero siempre mirando al punto \((0,0,0)\).
</p>
<p>
Recomendamos modificar libremente estos valores para poder observar los fractales desde distintos puntos de vista.
</p>
<h4>Epsilon</h4>
<p>
Anteriormente, cuando hemos explicado Sphere-Tracing, hemos mencionado que si se detecta que un punto está a una distancia muy pequeña de la superficie de algún objeto, entonces se considera que pertenece a esa superficie. Denominamos \(\varepsilon\) a esa distancia, la cual damos en este apartado la posibilidad de parametrizar. En general, tomando \(\varepsilon=10^{-3}\) se obtienen resultados bastante buenos.
</p>
<p>
Obsérvese cómo cambian el suelo, los fractales y su nivel de detalle al variar el valor de \(\varepsilon\).
</p>
<p>
<strong>CUIDADO</strong>: Cuanto menor sea esta cantidad mayor será la precisión y mejor la aproximación, pero también implica más carga de trabajo, por lo que no recomendamos utilizar el valor más pequeño ofrecido (que es \(10^{-4}\)) en modo interactivo en comunión con SSAA con un alto número de rayos por píxel o con las sombras activadas.
</p>
<h4>Supersampling Antialiasing</h4>
<p>
Anteriormente hemos mencionado que se identifica cada píxel con un único punto del plano de proyección, pero esto suele provocar calidades bajas y bordes bruscos. Con este parámetro se permite identificar cada píxel con \(n^2\) puntos, lanzar un rayo hacia cada punto, calcular el color asociado a cada rayo y finalmente asignar al píxel el color promedio. De esta forma se visualizan los bordes más suavizados y se obtienen imágenes de mayor calidad. Esta técnica se conoce como Supersampling Antialiasing (SSAA).
</p>
<p>
Recomendamos activar simultáneamente las sombras arrojadas, activar el antialiasing con un número alto de rayos por píxel y redibujar, el cambio es fácilmente notable (este procesado es lento y costoso, no recomendable usar el modo interactivo).
</p>
<p>
<strong>CUIDADO</strong>: Esta operación es considerablemente más costosa que el visualizado estándar, por lo que recomendamos no abusar de la interactividad con un número alto de rayos por píxel si no se dispone de una gráfica suficientemente buena.
</p>
<h3>Modelo de iluminación</h3>
<p>
En este apartado se ajustan los parámetros asociados al modelo de iluminación aplicado a la escena. Primeramente, aclaramos que el material asociado al fractal es parametrizable, pudiendo modificar el color de sus componentes ambiental, difusa, especular y el exponente de brillo, que procedemos a explicar.
</p>
<ul>
<li><strong>Componente ambiental</strong>: Se aplica por igual a todos los puntos del objeto sin tener en cuenta las luces que lo alumbran. Algo así como el color base o el color que se observa en las sombras.</li>
<li><strong>Componente difusa</strong>: A grandes rasgos, es el color mate del objeto cuando la luz incide sobre él.</li>
<li><strong>Componente especular</strong>: Color de los brillos metalizados del objeto en caso de que se desee este efecto.</li>
<li><strong>Brillo</strong>: Intensidad del brillo, "cuánto reluce".</li>
</ul>
<p>
Es recomendable, para notar el efecto de cada componente, dejar en negro dos de ellas y darle color a la restante para observar qué función tiene.
</p>
<p>
Sobre las luces, la escena está dotada de dos fuentes de luz que alumbran desde arriba, una desde la derecha y otra desde la izquierda. Cada una de ellas permite parametrizar su color y si arroja o no sombras.
</p>
<p>
Recomendamos subir un poco en la escena, con la tecla de la flecha hacia arriba o aumentando la coordenada \(y\) del parámetro <a href="#ayuda-posicion-actual" class="text-primary">posición actual</a> y activar y desactivar las sombras, para así poder ver los efectos de las sombras sobre el propio fractal y sobre el suelo.
</p>
<p>
<strong>CUIDADO</strong>: Arrojar sombras provoca un efecto muy realista pero también muy costoso, por lo que se recomienda no abusar del modo interactivo con las sombras activadas.
</p>
<div class="row align-items-center">
<img class="col-3" style="width: 70px;" src="static/img/warning.png">
<h2 class="col-9">ADVERTENCIA</h2>
</div>
<p>
Como se ha mencionado anteriormente, es posible que su dispositivo no soporte interactividad de forma fluida si se usa simultáneamente SSAA con un número elevado de rayos por píxel, sombras arrojadas y/o un valor de \(\varepsilon\) muy pequeño. Recomendamos por ello usar el modo interactivo con SSAA y sombras desactivadas y \(\varepsilon=0.001\), pudiendo utilizar los movimientos de la cámara libremente (aunque tampoco es recomendable mantener las teclas pulsadas dependiendo de la GPU). Si se desea un nivel de detalle mayor, se recomienda activar el modo a demanda, los parámetros más exigentes y redibujar.
</p>
<p>
En caso de que la web se sobrecargue, es posible que se ponga en blanco la pantalla y aparezca un mensaje de error. No se preocupe, en este caso debe ser suficiente una simple recarga de la página para solucionarlo, aunque en ciertos casos puede ser necesario reiniciar el navegador.
</p>
</section>
</main>
<!--
-- ─── PIE DE PAGINA ───────────────────────────────────────────────
-->
<footer class="d-flex flex-wrap justify-content-between align-items-center py-3 my-4 border-top">
<div class="col-md-4 d-flex align-items-center">
<a href="index.html" class="mb-3 me-2 mb-md-0 text-muted text-decoration-none lh-1">
<img src="static/img/logo.png" id="logo">
</a>
</div>
<div class="col-md-4 d-flex align-items-center justify-content-center">
<span class="mb-3 mb-md-0 text-muted">© 2022, Juan Antonio Villegas Recio</span>
</div>
<ul class="nav col-md-4 justify-content-end list-unstyled d-flex">
<li class="ms-3"><a href="https://github.com/JAntonioVR" class="fa fa-github"></a></li>
<li class="ms-3"><a href="https://www.linkedin.com/in/juan-antonio-villegas-recio/" class="fa fa-linkedin"></a></li>
<li class="ms-3"><a href="https://www.instagram.com/juanantonio_79/" class="fa fa-instagram"></a></li>
<li class="ms-3"><a href="https://www.facebook.com/profile.php?id=100010525867626" class="fa fa-facebook"></a></li>
<li class="ms-3"><a href="mailto:juanantoniovr98@gmail.com" class="fa fa-google"></a></li>
</ul>
</footer>
</body>
</html>