mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
More writing
This commit is contained in:
parent
a5e620f603
commit
b526b02e7b
@ -170,11 +170,11 @@ Thus, by applying the functions in our system to "fixed points," we will find th
|
|||||||
However, this is all a bit vague, so let's work through an example.
|
However, this is all a bit vague, so let's work through an example.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>But if you want a bit more math...</summary>
|
<summary>If you want a bit more math first...</summary>
|
||||||
|
|
||||||
...then it's worth mentioning some information I've skipped over.
|
...then there are some details worth mentioning that I've glossed over so far.
|
||||||
|
|
||||||
First, the Hutchinson paper explains that the functions $F_i$ must be _contractive_ for this result to hold.
|
First, the Hutchinson paper requires that the functions $F_i$ be _contractive_ tor the solution set to exist.
|
||||||
That is, applying the function to a point must bring it closer to other points. However, as the Fractal Flame
|
That is, applying the function to a point must bring it closer to other points. However, as the Fractal Flame
|
||||||
algorithm demonstrates, we only need functions to be contractive _on average_. At worst, the system will
|
algorithm demonstrates, we only need functions to be contractive _on average_. At worst, the system will
|
||||||
degenerate and produce a bad image.
|
degenerate and produce a bad image.
|
||||||
@ -200,7 +200,7 @@ $$
|
|||||||
### The chaos game
|
### The chaos game
|
||||||
|
|
||||||
Next, how do we find the "fixed points" we mentioned earlier? The paper lays out an algorithm called the "[chaos game](https://en.wikipedia.org/wiki/Chaos_game)"
|
Next, how do we find the "fixed points" we mentioned earlier? The paper lays out an algorithm called the "[chaos game](https://en.wikipedia.org/wiki/Chaos_game)"
|
||||||
that will give us points in the solution set:
|
that will give us points in the solution set.
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\begin{align*}
|
\begin{align*}
|
||||||
@ -213,7 +213,11 @@ $$
|
|||||||
\end{align*}
|
\end{align*}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
Let's turn this into code, one piece at a time.
|
:::note
|
||||||
|
In effect, the chaos game algorithm implements the "finite compositions of $F_{i_1..i_p}$ mentioned earlier.
|
||||||
|
:::
|
||||||
|
|
||||||
|
Now, let's turn this into code, one piece at a time.
|
||||||
|
|
||||||
First, the "bi-unit square" is the range $[-1, 1]$. We can :
|
First, the "bi-unit square" is the range $[-1, 1]$. We can :
|
||||||
|
|
||||||
@ -272,10 +276,13 @@ I think the paper has an error, so I'm choosing to plot the image
|
|||||||
in a way that's consistent with [`flam3` itself](https://github.com/scottdraves/flam3/blob/7fb50c82e90e051f00efcc3123d0e06de26594b2/rect.c#L440-L441).
|
in a way that's consistent with [`flam3` itself](https://github.com/scottdraves/flam3/blob/7fb50c82e90e051f00efcc3123d0e06de26594b2/rect.c#L440-L441).
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
## Weights
|
### Weights
|
||||||
|
|
||||||
Finally, we'll introduce a "weight" parameter ($w_i$) assigned to each function, which controls
|
Finally, we'll introduce a "weight" ($w_i$) for each function that controls how often we choose
|
||||||
how often that function is used:
|
that function during the chaos game relative to each other function.
|
||||||
|
|
||||||
|
For Sierpinski's Gasket, we start with equal weighting,
|
||||||
|
but you can see how changing the function weights affects the image below:
|
||||||
|
|
||||||
import randomChoiceSource from '!!raw-loader!../src/randomChoice'
|
import randomChoiceSource from '!!raw-loader!../src/randomChoice'
|
||||||
|
|
||||||
@ -289,3 +296,12 @@ import GasketWeighted from "./GasketWeighted";
|
|||||||
import {SquareCanvas} from "../src/Canvas";
|
import {SquareCanvas} from "../src/Canvas";
|
||||||
|
|
||||||
<SquareCanvas><GasketWeighted/></SquareCanvas>
|
<SquareCanvas><GasketWeighted/></SquareCanvas>
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Studying the foundations of fractal flames is challenging,
|
||||||
|
but we now have an understanding of both the mathematics
|
||||||
|
and implementation of iterated function systems.
|
||||||
|
|
||||||
|
In the next post, we'll study the first innovation that fractal flames
|
||||||
|
bring: variations.
|
@ -6,20 +6,22 @@ authors: [bspeice]
|
|||||||
tags: []
|
tags: []
|
||||||
---
|
---
|
||||||
|
|
||||||
Now that we have a basic chaos game in place, it's time to spice things up. Transforms and variations create the
|
Now that we have a basic chaos game in place, it's time to spice things up. Variations create the
|
||||||
shapes and patterns that fractal flames are known for.
|
shapes and patterns that fractal flames are known for.
|
||||||
|
|
||||||
<!-- truncate -->
|
<!-- truncate -->
|
||||||
|
|
||||||
:::note
|
:::info
|
||||||
This post uses a set of [reference parameters](../params.flame) to demonstrate the fractal flame algorithm.
|
This post uses a set of [reference parameters](../params.flame) to demonstrate the fractal flame algorithm.
|
||||||
If you're interested in tweaking the parameters, or generating your own art, [Apophysis](https://sourceforge.net/projects/apophysis/)
|
If you're interested in tweaking the parameters, or generating your own art, [Apophysis](https://sourceforge.net/projects/apophysis/)
|
||||||
can load that file and you can try tweaking things yourself!
|
can load that file and you can try tweaking things yourself!
|
||||||
|
|
||||||
This post covers section 3 of the Fractal Flame Algorithm paper
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
## Transforms and variations
|
## Variations
|
||||||
|
|
||||||
|
:::note
|
||||||
|
This post covers section 3 for the Fractal Flame Algorithm paper
|
||||||
|
:::
|
||||||
|
|
||||||
import CodeBlock from '@theme/CodeBlock'
|
import CodeBlock from '@theme/CodeBlock'
|
||||||
|
|
||||||
@ -28,8 +30,8 @@ playing the chaos game leads to an image of Sierpinski's Gasket. Even though we
|
|||||||
the image it generates is exciting. But it's still not nearly as exciting as the images the Fractal Flame
|
the image it generates is exciting. But it's still not nearly as exciting as the images the Fractal Flame
|
||||||
algorithm is known for.
|
algorithm is known for.
|
||||||
|
|
||||||
This leads us to the first big innovation of the Fractal Flame algorithm: using non-linear functions
|
This leads us to the first big innovation of the Fractal Flame algorithm: applying non-linear functions
|
||||||
for the transforms. These functions are known as "variations":
|
after the affine transform has happened. These functions are called "variations":
|
||||||
|
|
||||||
$$
|
$$
|
||||||
F_i(x, y) = V_j(a_i \cdot x + b_i \cdot y + c_i, d_i \cdot x + e_i \cdot y + f_i)
|
F_i(x, y) = V_j(a_i \cdot x + b_i \cdot y + c_i, d_i \cdot x + e_i \cdot y + f_i)
|
||||||
@ -39,10 +41,10 @@ import variationSource from '!!raw-loader!../src/variation'
|
|||||||
|
|
||||||
<CodeBlock language="typescript">{variationSource}</CodeBlock>
|
<CodeBlock language="typescript">{variationSource}</CodeBlock>
|
||||||
|
|
||||||
Variations, labeled $V_j$ above, are functions just like transforms (we use $j$ to indicate a specific variation).
|
Just like transforms, variations ($V_j$) are functions that map $(x, y)$ coordinates to new coordinates.
|
||||||
They take an input point $(x,y)$, and give an output point. However, the sky is the limit for what variation functions do in between
|
However, the sky is the limit for what we can do in between input and output.
|
||||||
input to output. The Fractal Flame paper lists 49 different variation functions,
|
The Fractal Flame paper lists 49 different variation functions,
|
||||||
and the official `flam3` implementation supports [98 different functions](https://github.com/scottdraves/flam3/blob/7fb50c82e90e051f00efcc3123d0e06de26594b2/variations.c).
|
and the official `flam3` implementation supports [98 different variations](https://github.com/scottdraves/flam3/blob/7fb50c82e90e051f00efcc3123d0e06de26594b2/variations.c).
|
||||||
|
|
||||||
To draw our reference image, we'll focus on four variations:
|
To draw our reference image, we'll focus on four variations:
|
||||||
|
|
||||||
@ -59,16 +61,16 @@ import linearSrc from '!!raw-loader!../src/linear'
|
|||||||
<CodeBlock language={'typescript'}>{linearSrc}</CodeBlock>
|
<CodeBlock language={'typescript'}>{linearSrc}</CodeBlock>
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
|
In a way, we've already been using this variation! The transforms that define Sierpinski's Gasket
|
||||||
In a way, we've already been using this variation! The functions that define Sierpinski's Gasket
|
|
||||||
apply the affine coefficients to the input point, and use that as the output point.
|
apply the affine coefficients to the input point, and use that as the output point.
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
### Julia (variation 13)
|
### Julia (variation 13)
|
||||||
|
|
||||||
This variation is a good example of the non-linear functions the Fractal Flame Algorithm introduces.
|
This variation is a good example of the non-linear functions we can use. It uses both trigonometry
|
||||||
It still receives an input point $(x, y)$, but does some crazy things with it:
|
and probability to produce interesting shapes:
|
||||||
|
|
||||||
|
TODO: Connection with the julia set?
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\begin{align*}
|
\begin{align*}
|
||||||
@ -91,8 +93,8 @@ import juliaSrc from '!!raw-loader!../src/julia'
|
|||||||
|
|
||||||
### Popcorn (variation 17)
|
### Popcorn (variation 17)
|
||||||
|
|
||||||
Some variations rely on knowing the transform's affine coefficients; these are known as "dependent variations."
|
Some variations rely on knowing their transform's affine coefficients; they're known as "dependent variations."
|
||||||
For the popcorn variation, we use the $c$ and $f$ coefficients:
|
For the popcorn variation, we use $c$ and $f$:
|
||||||
|
|
||||||
$$
|
$$
|
||||||
V_{17}(x,y) = (x + c \cdot \text{sin}(\text{tan }3y), y + f \cdot \text{sin}(\text{tan }3x))
|
V_{17}(x,y) = (x + c \cdot \text{sin}(\text{tan }3y), y + f \cdot \text{sin}(\text{tan }3x))
|
||||||
@ -104,7 +106,7 @@ import popcornSrc from '!!raw-loader!../src/popcorn'
|
|||||||
|
|
||||||
### PDJ (variation 24)
|
### PDJ (variation 24)
|
||||||
|
|
||||||
Some variations have extra parameters that the designer can choose; these are known as "parametric variations."
|
Some variations have extra parameters we can choose; these are known as "parametric variations."
|
||||||
For the PDJ variation, there are four extra parameters we can choose:
|
For the PDJ variation, there are four extra parameters we can choose:
|
||||||
|
|
||||||
$$
|
$$
|
||||||
@ -132,14 +134,11 @@ import blendSource from "!!raw-loader!../src/blend";
|
|||||||
|
|
||||||
<CodeBlock language={'typescript'}>{blendSource}</CodeBlock>
|
<CodeBlock language={'typescript'}>{blendSource}</CodeBlock>
|
||||||
|
|
||||||
With that in place, we have enough to render a first full fractal flame. We'll use the same
|
With that in place, we have enough to render a first fractal flame. We'll use the same
|
||||||
chaos game as before, but use our new transforms and variations to produce a dramatically different image:
|
chaos game as before, but our new transforms and variations produce a dramatically different image:
|
||||||
|
|
||||||
:::tip
|
:::tip
|
||||||
This image is interactive! The sliders change the variation weights ($v_{ij}$ parameters)
|
Try using the variation weight sliders to figure out which parts of the image each transform controls.
|
||||||
so you can design your own image.
|
|
||||||
|
|
||||||
Try using the sliders to find which parts of the image each transform controls.
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
import {SquareCanvas} from "../src/Canvas";
|
import {SquareCanvas} from "../src/Canvas";
|
||||||
@ -149,8 +148,8 @@ import FlameBlend from "./FlameBlend";
|
|||||||
|
|
||||||
## Post transforms
|
## Post transforms
|
||||||
|
|
||||||
Post transforms introduce a second affine transform, this time _after_ variation blending.
|
Next, we'll introduce a second affine transform, known as a post transform, that is applied _after_ variation blending.
|
||||||
We'll use introduce some new variables, but the post transform function should look familiar by now:
|
We'll use some new variables, but the post transform function should look familiar:
|
||||||
|
|
||||||
$$
|
$$
|
||||||
\begin{align*}
|
\begin{align*}
|
||||||
@ -163,11 +162,11 @@ import postSource from '!!raw-loader!./post'
|
|||||||
|
|
||||||
<CodeBlock language="typescript">{postSource}</CodeBlock>
|
<CodeBlock language="typescript">{postSource}</CodeBlock>
|
||||||
|
|
||||||
The image below starts with the same initial transforms/variations as the previous fractal flame,
|
The image below uses the same transforms/variations as the previous fractal flame,
|
||||||
but allows modifying the post-transform coefficients.
|
but allows modifying the post-transform coefficients.
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>If you want a challenge...</summary>
|
<summary>If you want to test your understanding...</summary>
|
||||||
|
|
||||||
Challenge 1: What post-transform coefficients will give us the previous image?
|
Challenge 1: What post-transform coefficients will give us the previous image?
|
||||||
|
|
||||||
@ -180,6 +179,11 @@ import FlamePost from "./FlamePost";
|
|||||||
|
|
||||||
## Final transforms
|
## Final transforms
|
||||||
|
|
||||||
|
Our last step is to introduce a "final transform" ($F_{final}$) that is applied
|
||||||
|
regardless of which transform function we're using. It works just like a normal transform
|
||||||
|
(composition of affine transform, variation blend, and post transform),
|
||||||
|
but it doesn't change the chaos game state:
|
||||||
|
|
||||||
import chaosGameFinalSource from "!!raw-loader!./chaosGameFinal"
|
import chaosGameFinalSource from "!!raw-loader!./chaosGameFinal"
|
||||||
|
|
||||||
<CodeBlock language="typescript">{chaosGameFinalSource}</CodeBlock>
|
<CodeBlock language="typescript">{chaosGameFinalSource}</CodeBlock>
|
||||||
@ -187,3 +191,11 @@ import chaosGameFinalSource from "!!raw-loader!./chaosGameFinal"
|
|||||||
import FlameFinal from "./FlameFinal";
|
import FlameFinal from "./FlameFinal";
|
||||||
|
|
||||||
<SquareCanvas><FlameFinal/></SquareCanvas>
|
<SquareCanvas><FlameFinal/></SquareCanvas>
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Variations are the fractal flame algorithm's first major innovation over previous IFS's.
|
||||||
|
Blending variation functions and post/final transforms allows us to generate interesting images.
|
||||||
|
|
||||||
|
However, the images themselves are grainy and unappealing. In the next post, we'll clean up
|
||||||
|
the quality and add color.
|
@ -11,8 +11,8 @@ to a specific pixel, and color in that pixel.
|
|||||||
This works well for simple function systems (like Sierpinski's Gasket),
|
This works well for simple function systems (like Sierpinski's Gasket),
|
||||||
but more complex systems (like our reference parameters) produce grainy images.
|
but more complex systems (like our reference parameters) produce grainy images.
|
||||||
|
|
||||||
Every time we "turn on" pixels that have already been enabled, we're wasting work.
|
Every additional time we plot a pixel, we're wasting work.
|
||||||
Can we do something more intelligent with that information?
|
Can we do something more intelligent instead?
|
||||||
|
|
||||||
<!-- truncate -->
|
<!-- truncate -->
|
||||||
|
|
||||||
@ -23,8 +23,12 @@ This post covers sections 4 and 5 of the Fractal Flame Algorithm paper
|
|||||||
:::
|
:::
|
||||||
|
|
||||||
To start with, it's worth demonstrating how much work is actually "wasted."
|
To start with, it's worth demonstrating how much work is actually "wasted."
|
||||||
We'll render the reference image again, but this time, set each pixel's transparency
|
Previously, pixels would be either transparent or opaque depending on whether
|
||||||
based on how many times we encounter it in the chaos game:
|
we encountered them while running the chaos game.
|
||||||
|
|
||||||
|
We'll render the reference image again, but this time, keep track of how many times
|
||||||
|
we encounter each pixel during the chaos game. At the end, we'll "paint" our final image
|
||||||
|
by setting each pixel's transparency based on how frequently we encounter it:
|
||||||
|
|
||||||
import CodeBlock from "@theme/CodeBlock";
|
import CodeBlock from "@theme/CodeBlock";
|
||||||
|
|
||||||
@ -40,6 +44,24 @@ import {paintLinear} from "./paintLinear";
|
|||||||
|
|
||||||
## Log display
|
## Log display
|
||||||
|
|
||||||
|
Using a histogram to paint our image is definitely a quality improvement,
|
||||||
|
but it produces "ghostly" images. In our reference parameters, the outer circle
|
||||||
|
is preserved, but the interior appears to be missing!
|
||||||
|
|
||||||
|
To fix this, we'll introduce the second major innovation of the fractal flame algorithm: tone mapping.
|
||||||
|
This technique is used in computer graphics to adjust for the fact that
|
||||||
|
people perceive brightness on a logarithmic scale.
|
||||||
|
|
||||||
|
As a concrete example, high dynamic range (HDR) photography uses this technique to capture
|
||||||
|
nice images of scenes with very different brightness levels. If you want to take a picture of something dark,
|
||||||
|
you need a long exposure time. However, long exposures lead to bright spots that "wash out" and become nothing but white.
|
||||||
|
If we take multiple images using different exposure times, we can blend them together to create
|
||||||
|
a final image where everything is visible.
|
||||||
|
|
||||||
|
TODO: HDR link?
|
||||||
|
|
||||||
|
In fractal flames, this "tone map" is accomplished
|
||||||
|
|
||||||
import paintLogarithmicSource from "!!raw-loader!./paintLogarithmic"
|
import paintLogarithmicSource from "!!raw-loader!./paintLogarithmic"
|
||||||
|
|
||||||
<CodeBlock language="typescript">{paintLogarithmicSource}</CodeBlock>
|
<CodeBlock language="typescript">{paintLogarithmicSource}</CodeBlock>
|
||||||
|
Loading…
Reference in New Issue
Block a user