Fractal Architect 5 Help Index
Applies to:FA 5
See Also: Using Lua Scripts
Lua version 5.2.3 interpreter has been added to the app. When you search for info, make sure you specify that Lua version number, as it is continually being updated with no language features / API changes.
Ralf Flicker wrote an excellent Lua primer for scripting fractals on the Oxidizer flame fractal app. (No longer maintained by its developer it seems.)
His Oxidizer Lua scripts and Lua Primer can be downloaded here:
Tutorial and Example Lua Scripts
Ralf was a brilliant scripter. Tweaked versions of his simil3.lua and simil4.lua scripts are included with Fractal Architect and show the full power of Lua when applied to flame fractal creation.
You may create your own reusable Lua modules to hold reusable Lua functions that you create. Custom scripts will use the Lua require function to load any modules the script wants to use.
Lua require functions search for Lua modules by looking in these directories, in this order:
- My Scripts/makeRandom
- My Scripts/makeVariants
- Factory/makeRandom
- Factory/makeVariants
The My Scripts folder’s location is can be changed by pressing the Choose Folder for My Scripts button.
The factory Lua tweak scripts provided with the app includes 2 example Lua modules and some example scripts that use those modules. (See below for more info.)
Fractal Architect uses several Lua global variables that it expects scripts to use for sending fractal definitions back to the app.
Note: Most scripts just setup the flame variable, not the layerz variable. In this case, a layered fractal is created that only has one layer.
The best example for creating layered fractals from Lua is the main script: makeLayers.lua.
(Note the *oxidizer_genomes* table is actually the same table. It is intended for compatibility with older Oxidizer Lua scripts created specifically for the Oxidizer app).
Fractals in Lua are represented as a single Lua table.
That table holds a complex assortment of other tables representing other data structures needed by the fractal definition.
It is recommended that you use the Fractal creation utility functions
to create a empty fractal (instead of setting each and every field shown in the table below).
In Lua, the layerz table has child layer tables that each represent a basic fractal.
There is no separate “layer” table, instead the “flame” table is used as the layer (and it has a “layerWeight” member).
So layerz[n] is the n-th layer and is a basic fractal.
flame.colors {tables, one per index}
flame.colors[n].index
flame.colors[n].red
flame.colors[n].green
flame.colors[n].blue
flame.colors[n].alpha
flame.background {table}
flame.background.red
flame.background.green
flame.background.blue
flame.composite_color {table} - for use with compositing render mode (see below)
flame.composite_color.red
flame.composite_color.green
flame.composite_color.blue
flame.xforms[n].coefs - 2D pre matrix coefficients
flame.xforms[n].coefs3D - 3D pre matrix coefficients
flame.finalxforms[n].coefs - 2D pre matrix coefficients
flame.finalxforms[n].coefs3D - 3D pre matrix coefficients
flame.xforms[n].variations {table - one table per variation instance}
flame.xforms[n].preVarGroups {table - one table per Pre variation group}
flame.xforms[n].postVarGroups {table - one table per Post variation group}
Here we are creating a “matrix2d” variation instance,
randomizing the matrix,
then creating a new variation group and appending it onto the variation chain.
matrix2d = { name=“matrix2d”, weight=1., coefs=makeCoefs() }
randomPreMatrix(matrix2d)
table.insert(chain, { matrix2d })
Here we are creating a “matrix3d” variation instance,
randomizing the matrix,
then creating a new variation group and appending it onto the variation chain.
matrix3d = { name=“matrix3d”, weight=1., coefs3D=makeCoefs3D() }
randomPreMatrix(matrix3d)
table.insert(chain, { matrix3d })
identity matrix:
[ 1 0 0 ] where [ a b c ]
[ 0 1 0 ] [ d e f ]
identity matrix:
[ 1 0 0 ] where [ a b c ]
[ 0 1 0 ] [ d e f ]
identity matrix:
[ 1 0 0 0] where [ a b c d ]
[ 0 1 0 0 ] [ e f g h ]
[ 0 0 1 0 ] [ i j k l ]
identity matrix:
[ 1 0 0 0] where [ a b c d ]
[ 0 1 0 0 ] [ e f g h ]
[ 0 0 1 0 ] [ i j k l ]
A Varpar table is a Lua table specifying both a variation type, its weight, and values for all of its parameters.
Varpar is just an acronym that indicates a variation instance plus its parameter values.
For example, to add a julian instance to an xform:
varpar = { name="julian", weight = 0.4, julian_power = 3, julian_dist = 0.75 } table.insert(xform.variations, varpar)
This example specifies a julian variation type, its variation weight,
and values for both its weight and dist parameters.
FA 5 now includes ability for one Lua script to call a different Lua script.
Most Make Fractal scripts will use include this Lua package file. This is how they include the package file.
require("Utils")
This file written by Ralf Flicker and used in his scripts and other Lua scripts has some
functions to rotate, scale and translate an xform’s Pre triangle. (The Triangle is just a way to graphically show the affect of the matrix transformation.)
====================== 2D Matrix ===============
| a b c |
| d e f |
stored as transposed matrix:
coefs = {
{ a, d },
{ b, e },
{ c, f } }
affine_rotate (xform,phs) OR affine_Prot (xform,phs)
xform - the xform table
phs - the rotation amount in degrees units
affine_Orot (xform,phs)
xform - the xform table
phs - the rotation amount in degrees units
affine_translate (xform,x,y)
xform - the xform table
x - the translation along the X axis
y - the translation along the Y axis
affine_scale (xform,sf)
xform - the xform table
sf - the scale factor
postAffine_rotate (xform,phs) OR postAffine_Prot (xform,phs)
xform - the xform table
phs - the rotation amount in degrees units
postAffine_Orot (xform,phs)
xform - the xform table
phs - the rotation amount in degrees units
postAffine_translate (xform,x,y)
xform - the xform table
x - the translation along the X axis
y - the translation along the Y axis
Scale the xform Post-matrix triangle (relative to the Triangle’s own origin)
postAffine_scale (xform,sf)
xform - the xform table
sf - the scale factor
randomPreMatrix (xform)
xform - the xform table
randomPostMatrix (xform)
xform - the xform table
====================== 3D Matrix ===============
| a b c d |
| e f g h |
| i j k l |
| 0 0 0 1 |
stored as transposed matrix
coefs3D = {
{ a, e, i },
{ b, f, j },
{ c, g, k },
{ d, h, l } }
affine_rotate3D (xform, yaw, pitch, roll)
xform - the xform table
yaw - yaw rotation amount in degrees units
pitch - pitch rotation amount in degrees units
roll - roll rotation amount in degrees units
affine_translate3D (xform,x,y,z)
xform - the xform table
x - the translation along the X axis
y - the translation along the Y axis
z - the translation along the Z axis
affine_uscale3D (xform,sf)
xform - the xform table
sf - the scale factor
affine_scale3D (xform,sfx,sfy,sfz)
xform - the xform table
sfx - the X scale factor
sfy - the Y scale factor
sfz - the Z scale factor
postAffine_rotate3D (xform, yaw, pitch, roll)
xform - the xform table
yaw - yaw rotation amount in degrees units
pitch - pitch rotation amount in degrees units
roll - roll rotation amount in degrees units
postAffine_translate3D(xform,x,y,z)
xform - the xform table
x - the translation along the X axis
y - the translation along the Y axis
z - the translation along the Z axis
postAffine_scale3D (xform,sfx,sfy,sfz)
xform - the xform table
sf - the scale factor
randomPreMatrix3D (xform)
xform - the xform table
randomPostMatrix3D (xform)
xform - the xform table
The 2 dimensional transformation matrix used by most flame renderers today all have 6 values in each transformation matrix. Each Xform structure in a flame fractal has two transformation matrices: coefs and post.
The Fractal Architect app refers to the Lua coefs matrix table as the Pre matrix, and the Lua post matrix table as the Post matrix.
Special Rule: Matrix variation types have a coefs matrix table too.
NOTE: A little confusion between FA/flam3 and Apophysis notation for the individual transformation matrix fields a - f.
Apophysis uses column order labeling, whereas flam3/Factal Architect uses row order labeling.
The table below shows how to convert between the notations
upper case letters ==> Apophysis
lower case letters ==> flam3 and Fractal Architect
Flam3 labels - row ordered
| a b c |
| d e f |
Apophysis labels - column ordered
| A C E |
| B D F |
Lua Matrix Cell Indexing
| m[1][1] m[2][1] m[3][1] |
| m[1][2] m[2][2] m[3][2] |
Each row here all refers to the same matrix cell value:
coefs.a = coefs[1][1] = coefs.A(coefs) = coefs:A()
coefs.b = coefs[2][1] = coefs.C(coefs) = coefs:C()
coefs.c = coefs[3][1] = coefs.E(coefs) = coefs:E()
coefs.d = coefs[1][2] = coefs.B(coefs) = coefs:B()
coefs.e = coefs[2][2] = coefs.D(coefs) = coefs:D()
coefs.f = coefs[3][2] = coefs.F(coefs) = coefs:F()
post.a = post[1][1] = post.A(post) = post:A()
post.b = post[2][1] = post.C(post) = post:C()
post.c = post[3][1] = post.E(post) = post:E()
post.d = post[1][2] = post.B(post) = post:B()
post.e = post[2][2] = post.D(post) = post:D()
post.f = post[3][2] = post.F(post) = post:F()
These are the Apophysis-like getter/setter functions to make it easier to port Apophysis scripts to Lua.
3D fractal’s transforms are always 3D.
Each Xform structure in a 3D flame fractal has two transformation matrices: coefs3D and post3D.
The Fractal Architect app refers to the Lua coefs3D matrix table as the Pre 3D matrix, and the Lua post3D matrix table as the Post 3D matrix.
Special Rule: 3D Matrix variation types have a coefs3D matrix table too.
Flam3 labels - row ordered
| a b c d |
| e f g h |
| i j k l |
Lua Matrix Cell Indexing
| m[1][1] m[2][1] m[3][1] m[4][1] |
| m[1][2] m[2][2] m[3][2] m[4][2] |
| m[1][3] m[2][3] m[3][3] m[4][3] |
Each row here all refers to the same matrix cell value:
coefs3D.a = coefs3D[1][1]
coefs3D.b = coefs3D[2][1]
coefs3D.c = coefs3D[3][1]
coefs3D.d = coefs3D[4][1]
coefs3D.e = coefs3D[1][2]
coefs3D.f = coefs3D[2][2]
coefs3D.g = coefs3D[3][2]
coefs3D.h = coefs3D[4][2]
coefs3D.i = coefs3D[1][3]
coefs3D.j = coefs3D[2][3]
coefs3D.k = coefs3D[3][3]
coefs3D.l = coefs3D[4][3]
post3D.a = post3D[1][1]
post3D.b = post3D[2][1]
post3D.c = post3D[3][1]
post3D.d = post3D[4][1]
post3D.e = post3D[1][2]
post3D.f = post3D[2][2]
post3D.g = post3D[3][2]
post3D.h = post3D[4][2]
post3D.i = post3D[1][3]
post3D.j = post3D[2][3]
post3D.k = post3D[3][3]
post3D.l = post3D[4][3]
The variationset table holds all of the variations and their parameter info for the app’s current variation set. A variation set determines the variations available to the renderer (for a single fractal render). Fractal Architect can simultaneously render fractals that use different variation sets. However the Random Fractal Generator works uses a single Variation set for creating fractals. (Those fractals will all refer to that variation set.)
Scripts typically use the Variation Set information to learn what variations are available for the current variation set.
-- get the variations table for "julian" and return its name
varName = variationSet.variations.julian.variation
OR
varName = variationSet.variations["julian"].variation
-- Print the list of parameter names
for i, name in variationSet.variations.julian.param_names do
print(name)
end
-- Print the list of parameter names
for i, key in variationSet.variations.julian.param_keys do
print(key)
end
Finding if There Is a Variation Set That Covers the Required Variations,
if not it creates a new one
if not variationSet.hasVariations(requiredVariations) then
if not variationSet.switchToFirstVariationSetWithRequiredVariations(requiredVariations) then
local uuid = variationSet.makeSetWithVariations(requiredVariations, "Brokat3D")
if uuid and not variationSet.switchToVariationSetWithUuid(uuid) then
require("Linear")
return
end
end
end
Seeing if the current variaton set covers the required variatons.
If not it switches to one of the few “Standard” variation sets
if not variationSet.hasVariations(requiredVariations) then
variationSet.switchToVariationSetWithName("Flam3 Legacy")
end
The FA library has several useful functions for printing out intermediate results
GPU rendering tends to have higher noise at typical preview quality amounts. The multiplier here tells the app to increase the preview render by this quality multiplier.
Fractal Architect provides a couple of very useful factory modules:
Example usage in a custom Lua script:
In this example, a monochromatic color gradient is created, with a 20% probability of totally random colors being added because no weightRandom parameter is used.
The third line shows how to not have random colors added to the gradient.
local Gradients = require "GradientsModule" Gradients.monochromaticScheme() -- 20% probability of random color Gradients.monochromaticScheme(0.) -- 0% probability of random color
Gradients.analogousScheme(weightRandom)
weightRandom - probability that a totally random color will be chosen. Range between 0 and 1 inclusive. Default value = 0.2 (20% probability)
Gradients.complementaryScheme(weightRandom)
weightRandom - probability that a totally random color will be chosen. Range between 0 and 1 inclusive. Default value = 0.2 (20% probability)
Gradients.grayscaleScheme(weightRandom)
weightRandom - probability that a totally random color will be chosen. Range between 0 and 1 inclusive. Default value = 0.2 (20% probability)
Gradients.monochromaticScheme(weightRandom)
weightRandom - probability that a totally random color will be chosen. Range between 0 and 1 inclusive. Default value = 0.2 (20% probability)
Make color gradient using Random color scheme
Rotate color gradient by a random number of color stops
Example usage in a custom Lua script:
In this example, we are adding a Julian variation to the Pre Variation Group of every transform (probability of adding it to a transform here is 66.66667%).
local PrePostVariations = require "PrePostVariationsModule"
PrePostVariations.preVarPar(
{ name="julian", weight=2.*math.random(),
julian_power = math.random(1,3),
julian_dist = 0.1 + math.random() * 2.9},
0.666667) --66.6667% chance of adding Julian variation to Pre variation Group
Randomly insert the group of variation and variation parameters into the first Pre Variation Group of each transform.
varpars - table containing a list of variation names, variation weights, and their variation parameter values (if any)
weight - probability that the varpars is inserted - should be between 0. and 1 inclusive. Default value = 0.3 (30% probability)
Randomly insert the group of variation and variation parameters into the first Post Variation Group of each transform.
PrePostVariations.postVarPar(varpars, weight)
varpars - table containing a list of variation names, variation weights, and their variation parameter values (if any)
weight - probability that the varpars is inserted - should be between 0. and 1 inclusive. Default value = 0.3 (30% probability)
Randomly prepend new first Pre-Variation Group to each transform
then insert the varpars (group of variation and variation parameters) into the new Pre Variation Group.
PrePostVariations.prependNewPreVarGroup(varpars, weight)
varpars - table containing a list of variation names, variation weights, and their variation parameter values (if any)
weight - probability that the varpars is inserted - should be between 0. and 1 inclusive. Default value = 0.3 (30% probability)
Randomly append new first Pre-Variation Group to each transform
then insert the varpars (group of variation and variation parameters) into the new Pre Variation Group.
PrePostVariations.appendNewPreVarGroup(varpars, weight)
varpars - table containing a list of variation names, variation weights, and their variation parameter values (if any)
weight - probability that the varpars is inserted - should be between 0. and 1 inclusive. Default value = 0.3 (30% probability)
Randomly append new first Pre-Variation Group to each transform - but only if the pre var group list is not empty
then insert the varpars (group of variation and variation parameters) into the new Pre Variation Group.
PrePostVariations.appendAnotherNewPreVarGroup(varpars, weight)
varpars - table containing a list of variation names, variation weights, and their variation parameter values (if any)
weight - probability that the varpars is inserted - should be between 0. and 1 inclusive. Default value = 0.3 (30% probability)
Randomly prepend new first Post-Variation Group to each transform
then insert the varpars (group of variation and variation parameters) into the new Post Variation Group.
PostPostVariations.postpendNewPostVarGroup(varpars, weight)
varpars - table containing a list of variation names, variation weights, and their variation parameter values (if any)
weight - probability that the varpars is inserted - should be between 0. and 1 inclusive. Default value = 0.3 (30% probability)
Randomly append new first Post-Variation Group to each transform
then insert the varpars (group of variation and variation parameters) into the new Post Variation Group.
PostPostVariations.appendNewPostVarGroup(varpars, weight)
varpars - table containing a list of variation names, variation weights, and their variation parameter values (if any)
weight - probability that the varpars is inserted - should be between 0. and 1 inclusive. Default value = 0.3 (30% probability)
Randomly append new first Post-Variation Group to each transform - but only if the post var group list is not empty
then insert the varpars (group of variation and variation parameters) into the new Post Variation Group.
PostPostVariations.appendAnotherNewPostVarGroup(varpars, weight)
varpars - table containing a list of variation names, variation weights, and their variation parameter values (if any)
weight - probability that the varpars is inserted - should be between 0. and 1 inclusive. Default value = 0.3 (30% probability)
Call another script to create a subflame that will be added to “parent” flame.
Subflames.subflameFromScriptNamed(name, parent)
name - base file name of main Lua script that will create the new subflame
i.e. for “simil3.lua” it would be “simil3”
parent - the parent flame to which the subflame will be attached
Example usage in a custom Lua script:
In this example, we are creating a new sub-flame for the fractal flame. args.script is the main script name to run.
local M = require "SubflamesModule"
local subflameUuid = M.subflameFromScriptNamed(args.script, flame)
local xform = makeBlankXform()
table.insert(xform.variations, { name="subflame", weight=1., subflame_flame = subflameUuid })
table.insert(flame.xforms, xform)