IFS is short for Iterated Function System.

An IFS-fractal contains several functions which takes a point in space as parameter and returns another point in space based.
These functions are called transforms.

StyrofoamIFS uses the chaos game algorithm with these transforms to construct a point-cloud that is then raytraced in the next stage.
Points in space are represented by spheres which have radius, color and reflection.

Commands in a transform is executed in serie, their order may matter.

To create a new fractal you need to create a new .ifs file. Either copy an old one, or create a new from scratch in your text editor.

Words in *italics* can either be numerical values, variables or mathematical functions.

The | sign is used to delimit different identifiers.

Example: `x|y|z`

means that you can put either a 'x', an 'y' or a 'z' in that spot.

Anywhere where you can write a value, a mathematical formula will work as well.

Example: `let p,cos(pi*anim/36)`

Any time '//' is found on a row the rest of the row will be discarded as a comment.

Multiline-comments starts with '/*' and ends with '*/'.

See 2d variations for 2d-variants of variations.

**xform** [name][,name2,...]

The first row of a transform. The following commands only apply to this until the next transform.

A name can be given to a transform if it needs to be referenced later on.

Names don't need to be unique and will form a group of transforms.

If you give several names, several transforms will be created in parallell (see prefixing later for use of this).

Example: `xform 0`

**newmap** [name][,name2,...]

Same as xform.

Example: `newmap 0`

**tag** name[,name2,...]

Gives the transform one or more names. Transforms can have several names.

Example: `tag grp_a`

**ifs**

Stop applying commands to the current transform and hereafter apply commands to **all previous** transforms.

Example: `ifs`

**translate** *a*,*b*,*c*[,*d*]

Moves the point in space a given distance.

x,y and z are translated with the values a,b and c.

x=x+a, y=y+b, z=z+c, and if d is present, w=w+d

Example: `translate 0,0,-0.5`

**scale** *a*,*b*,*c*[,*d*]

x,y and z are scaled with the given values.

x=x*a, y=y*b, z=z*c, and if d is present, w=w*d

Example: `scale 0.5,0.5,0.5`

**scale** *a*

Shortcut for scale a,a,a

Example: `scale 0.5`

**rotate** x|y|z,*angle*

Rotate angle degrees around the axis given by the first parameter

Note that this angle is in degrees, not radians!

Example: `rotate x,45`

**rotate** *xaxis*,*yaxis*,*zaxis*,*angle*

Rotate angle degrees around the axis given by the vector xaxis,yaxis,zaxis

Note that this angle is in degrees, not radians!

Example: `rotate 1,1,0,45`

**power** *p*

Applies the geometric power.

Calculate angle and radius, and do radius ^ p

Example: `power -1`

**sinusoidal**

Based on the sinusoidal transform in Apophysis

x=sin(x), y=sin(y), z=sin(z)

Example: `sinusoidal`

**asinusoidal**

x=asin(clamp(x,-1,1)), y=asin(clamp(y,-1,1)), z=asin(clamp(z,-1,1))

Example: `asinusoidal`

**spherical**

Based on the spherical transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

x=x/r, y=y/r, z=z/r

Example: `spherical`

**swirl**

Based on the swirl transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

x=x*sin(r^{2})-y*cos(r^{2}), y=x*cos(r^{2})+y*sin(r^{2}), z=x*cos(r^{2})-z*sin(r^{2})

Example: `swirl`

**horseshoe**

Based on the horseshoe transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

x=(x-y)*(x+y)/r, y=2*x*y/r, z=(x-z)*(x+z)/r

Example: `horseshoe`

**polar**

Based on the polar transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

x=θ/π, y=r-1, z=θ_{2}/π

Example: `polar`

**handkerchief**

Based on the handkerchief transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

x=r*sin(θ+r), y=r*cos(θ-r), z=r*sin(θ_{2}+r)

Example: `handkerchief`

**heart**

Based on the heart transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

r_{1}=sqrt(x^{2}+y^{2})

r_{2}=sqrt(x^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

x=r*sin(θ*r_{1}), y=-r*cos(θ*r_{1}), z=-r*cos(θ_{2}*r_{2})

Example: `heart`

**disc**

Based on the disc transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

x=θ/π*sin(π*r), y=θ/π*cos(π*r), z=θ_{2}/π*cos(π*r)

Example: `disc`

**spiral**

Based on the spiral transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

x=(cos(θ)+sin(r))/r, y=(sin(θ)-cos(r))/r, z=(cos(θ_{2})+sin(r))/r

Example: `spiral`

**hyperbolic**

Based on the hyperbolic transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

x=sin(θ)/r, y=r*cos(θ), z=sin(θ_{2})/r

Example: `hyperbolic`

**diamond**

Based on the diamond transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

x=sin(θ)*cos(r), y=cos(θ)*sin(r), z=sin(θ_{2})*cos(r)

Example: `diamond`

**ex**

Based on the ex transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

p_{0}=sin(θ+r)

p_{1}=cos(θ-r)

p_{2}=sin(θ_{2}+r)

p_{3}=cos(θ_{2}-r)

x=r*(p_{0}^{3}+p_{1}^{3}), y=r*(p_{0}^{3}-p_{1}^{3}), z=r*(p_{2}^{3}-p_{3}^{3})

Example: `ex`

**julia**

Based on the julia transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

θ=atan(y/x)

θ_{2}=atan(z/x)

x=sqrt(r)*cos(θ/2), y=sqrt(r)*sin(θ/2), z=sqrt(r)*sin(θ_{2}/2)

Example: `julia`

**bent**

Based on the bent transform in Apophysis

x=x, y=y, z=z, x≥0, y≥0

x=2*x, y=y, z=2*z, x<0, y≥0

x=x, y=y/2, z=z/2, x≥0, y<0

x=2*x, y=y/2, z=z, x<0, y<0

Example: `bent`

**wave** *b*,*c*

Based on the wave transform in Apophysis

x=x+b*sin(y/c^{2}), y=y+b*sin(x/c^{2}), z=z+b*sin(z/c^{2})

Example: `wave 0.5,2`

**fisheye**

Based on the fisheye transform in Apophysis

r=sqrt(x^{2}+y^{2}+z^{2})

x=2*y/(r+1), y=2*x/(r+1), z=2*z/(r+1)

Example: `fisheye`

**popcorn** *h*

Based on the popcorn transform in Apophysis

x = x - h*sin(y + tan(3*y))

y = y - h*sin(z + tan(3*z))

z = z - h*sin(x + tan(3*x))

Example: `popcorn 0.1`

**exponential**

Based on the exponential transform in Apophysis

x=e^{x-1}*cos(π*y), y=e^{x-1}*sin(π*y), z=e^{x-1}*sin(π*z)

Example: `exponential`

**cosine**

Based on the cosine transform in Apophysis

x=cos(π*x)*cosh(y), y=-sin(π*x)*sinh(y), z=sin(x)

Example: `cosine`

**foci**

x=( 0.5*e^{x}-2*e^{-x} ) / ( 0.5*e^{x}+2*e^{-x} - cos(y)*cos(z))

y=sin(y) / ( 0.5*e^{x}+2*e^{-x} - cos(y)*cos(z))

z=sin(z) / ( 0.5*e^{x}+2*e^{-x} - cos(y)*cos(z))

Example: `foci`

**gnarl** *s*,*a*,*b*,*c*,*d*

repeat the following 16 times:

x' = x - s*sin(z + a*sin(b*z + c*y + d*x))

y' = y - s*sin(x + a*sin(b*x + c*z + d*y))

z' = z - s*sin(y + a*sin(b*y + c*x + d*z))

x = x', y = y', z = z'

y' = y - s*sin(x + a*sin(b*x + c*z + d*y))

z' = z - s*sin(y + a*sin(b*y + c*x + d*z))

x = x', y = y', z = z'

Example: `gnarl 0.05,3,2,0.2,0`

**linear** *a*,*b*,*c*,*d*,*e*,*f*

x = x * a + d

y = y * b + e

z = z * c + f

Example: `linear 0,0,0, 1,1,1`

**julian** *power*,*dist*

Based on the juliaN transform in Apophysis

θ=atan(y/x)

θ_{2}=atan(z/x)

r=sqrt(x^{2}+y^{2}+z^{2})

rnd=random number in [0,1]

x = r^{dist/power} * cos(θ + 2 * π * trunc(abs(power) * rnd))

y = r^{dist/power} * sin(θ + 2 * π * trunc(abs(power) * rnd))

z = r^{dist/power} * sin(θ_{2} + 2 * π * trunc(abs(power) * rnd))

Example: `julian 2,-1`

**blur**

Based on the blur transform in Apophysis

rnd=random number in [0,1]

rnd_{2}=random number in [0,1]

rnd_{3}=random number in [0,1]

x = rnd * cos(2 * π * rnd_{2})

y = rnd * sin(2 * π * rnd_{2})

z = rnd * sin(2 * π * rnd_{3})

Example: `blur`

**preblur**

Based on the pre_blur transform in Apophysis

The following values are stored between calls:

gauss_rnd_{0}=random number in [0,1]

gauss_rnd_{1}=random number in [0,1]

gauss_rnd_{2}=random number in [0,1]

gauss_rnd_{3}=random number in [0,1]

gauss_rnd_{4}=random number in [0,1]

gauss_rnd_{5}=random number in [0,1]

gauss_N=0

gauss_rnd

gauss_rnd

gauss_rnd

gauss_rnd

gauss_rnd

gauss_N=0

r=gauss_rnd_{0}+gauss_rnd_{1}+gauss_rnd_{2}+gauss_rnd_{3}+gauss_rnd_{4}+gauss_rnd_{5} - 3

rnd=random number in [0,1]

rnd_{2}=random number in [0,1]

x = r * sin(rnd * π) * cos(rnd_{2} * 2 * π)

y = r * sin(rnd * π) * sin(rnd_{2} * 2 * π)

z = r * cos(rnd * π)

Recalculate one stored value each call:

rnd=random number in [0,1]

rnd

x = r * sin(rnd * π) * cos(rnd

y = r * sin(rnd * π) * sin(rnd

z = r * cos(rnd * π)

Recalculate one stored value each call:

gauss_rnd_{gauss_N}=random number in [0,1]

gauss_N=gauss_N modulo 6

gauss_N=gauss_N modulo 6

Example: `preblur`

**center**

Stores the current position and moves the point to origo (0,0,0)

xstore=x, ystore=y, zstore=z

x=0, y=0, z=0

Example: `center`

**decenter**

Adds the position last stored with center

x=x+xstore, y=y+ystore, z=z+zstore

Example: `decenter`

**matrix_mul** *a*,*b*,*c*,*p*,*q*,*r*,*u*,*v*,*w*

Multiply | x | with the matrix | a | b | c | |

y | p | q | r | |||

z | u | v | w |

**sphere_radius** *r*

Sets the radius of the resulting point

Note that this applies to all radiuses from here onward, also from other transforms

Example: `sphere_radius 0.1`

**sphere_radius_factor** *f*

Deprecated!

Use sphere_radius base_sphere_radius*value instead.

Example: replace `sphere_radius_factor 0.5`

with `sphere_radius base_sphere_radius*0.5`

**sphere_grow** *r*

The resulting point will have its volume grown by r every time instead

Note that the number of iterations will influence the outcome.

Example: `sphere_grow 0.0002`

**reflection** *r*

The resulting point will have a reflectivness of r.

0=no reflection, 1=full reflection

See properties for more info.

Example: `reflection 0.5`

**color** *a*,*b*

The resulting point will have a its color taken from the palette at position a,b.

See properties for more info.

Example: `color 0,1`

**color** *r*,*g*,*b*

The resulting point will get the color r,g,b.

See properties for more info.

Example: `color 0.7,0.7,0.7`

**weight** *a*

Sets the probability factor that this transform will get picked in the chaos game.

Default weight is 1.

This command is not supported inside path conditions.

Example: `weight 0.07`

**xaos** name[,name2,...]

List the names of the transforms that can be reached from this transform.

Note that several transforms can have the same name and they will all be available.

If xaos is not used, all transforms can be reached.

This command is not supported inside path conditions.

Example: `xaos grp_a,grp_b`

**path** name[,name2,...]

...

**[else]**

...

**end**

Conditionally executes commands depending on the which transforms where executed previously.

Similar to if/then/else in common programming languages but applies to the path taken by the chaos game.

If any conditions don't apply, the commands after the path command won't be executed, up until the next else/end command.

Every path must have a closing end command, the else is optional.

The first position refers to the currently executed transform, the condition is met if it has one of the tags listed.

The next position refers to the previously executed transform, if it had one of the tags listed the condition is met.

The position after that refers to the transform executed two transforms ago, and so on.

Leaving a position empty means that any transform could have been executed.

Name can refer to any xform name or tag, if multiple tags should be allowed write `[tag1,tag2,...]`

.

To allow different paths on the same line, write `path (name,name2)(name3,name4)`

Weight and xaos commands are currently not supported inside path conditions.

Example:

`path ,,grp_a,[grp_a,grp_b]`

//commands here will only be executed if the transform executed two transforms ago had a grp_a tag

//and if the transform executed before that had either a grp_a or a grp_b tag

end

**sum** [w1,w2,...]

...

**endsum**

Calculates a weighted sum of commands instead of applying them in serially.

This is based on the flame formula that Apophysis is using except the concepts of post-transform and final transform is not applicable.

w1 is the weight of the first term, w2 the weight of the second and so on. All weights are set to 1 if w1 is left out.

If there are more commands than weights, the last weight will be used for the remaining commands.

Example:

`sum 1,0.1`

polar

preblur

endsum

**flame** [w1,w2,...]

...

**endflame**

Same as sum/endsum.

Example:

`flame 1,0.1`

polar

preblur

endflame

**model** filename,*scale*

Moves the x,y,z position to a random point in a 3d object given by a .ply file.

Use scale to scale the object.

Example: `model c:\temp\bun_zipper_res4.ply, 5`

**let** name,*value*

Defines a variable that can be used in calculations later.

Example: `let angle,45`

**color00** *r*,*g*,*b*

Sets the color of the 0,0 position in the palette.

See properties for more info.

Example: `color00 1,1,0.5`

**color01** *r*,*g*,*b*

Sets the color of the 0,1 position in the palette.

See properties for more info.

Example: `color01 1,0,0.5`

**color10** *r*,*g*,*b*

Sets the color of the 1,0 position in the palette.

See properties for more info.

Example: `color10 0,1,0.5`

**color11** *r*,*g*,*b*

Sets the color of the 1,1 position in the palette.

See properties for more info.

Example: `color11 0,0,0.5`

**color_png** filepath

Uses the color on an image as palette

Only png format is supported.
See properties for more info.

Example: `color_png D:\StyrofoamIFS\background\palette.png`

**draw** n

Transforms with draw 0 will not make a point in the point-cloud.

Note! Changed name from drawsphere.

Example: `draw 0`

**post_filter** x|y|z|w,*min*,*max*

Only points on the given axis between min and max will make it to the point cloud.

Example: `post_filter z,0,99`

**post_filter** plane,*normalx*,*normaly*,*normalz*[,*normalw*],*min*,*max*

Only points at a distance between min and max from the plane given by normalx,normaly,normalz and optionally normalw will make it to the point cloud.

Example: `post_filter plane,1,1,1,-99,0`

**post_filter** radius3d[,*centerx*,*centery*,*centerz*],*min*,*max*

Only points at a radius between min and max from origo (or from a point at centerx,centery,centerz) will make it to the point cloud.

Example: `post_filter radius3d,0.5,1`

**post_filter** radius4d[,*centerx*,*centery*,*centerz*,*centerw*],*min*,*max*

Only points at a radius between min and max from origo (or from a point at centerx,centery,centerz,centerw) will make it to the point cloud.

Example: `post_filter radius4d,0.5,1`

**print** *v*

Print a variable to output. Used for debugging.

Example: `print pi`

Prefixing rows with [name,name2,...] makes only transforms with the names inside the brackets get the command.
This is useful when defining several transforms at the same time.
Prefixing only works for commands that apply to the current transform.

Example:

```
xform a,b,c //create three transforms, one named "a", one named "b", one named "c"
```

scale 0.5 //all three transforms will get this line

[a]transform 0.5,0.5,0 //only transform a will get this line

[b,c]transform 0.5,-0.5,0 //only transforms b and c will get this line

pi |
3.14159265358979323846 |

e |
2.71828182845904523536 |

anim |
The current frame |

All parameters in the .scene file is automatically imported as variables.

Most of these functions are the same as their standard C/C++ counterpart and left without comment.

sin(a) | |

cos(a) | |

tan(a) | |

sinh(a) | |

cosh(a) | |

tanh(a) | |

asin(a) | |

acos(a) | |

atan(a) | |

asinh(a) | |

acosh(a) | |

atanh(a) | |

sqrt(a) | |

log(a) | |

log2(a) | |

log10(a) | |

abs(a) | |

ceil(a) | |

floor(a) | |

rad(a) | Convert a degrees to radians |

deg(a) | Convert a radians to degrees |

step(a) | Returns 1 if a >=0, else 0 |

rnd(a) | Random value between 0 and a |

pow(a,b) | |

max(a,b) | |

min(a,b) | |

atan2(a,b) | |

fmod(a,b) | Modulo |

remainder(a,b) | |

step(a,b) | Returns 1 if a >=0 and b < 0, else 0 |

clamp(a,b,c) | Clamps a between b (min) and c (max) |