ofxRules Addon for openFrameworks
ofxRules /o əfɛkts rulz/
1. abbreviation
Polite form of openFrameworksFreakinRulesDooood
2. noun
ofxRules – https://github.com/neilmendoza/ofxRules – is an addon for openFrameworks for generatively creating 3D meshes based on sets of rules (normally contained within XML files). Using this approach it is quick to create complex organic looking 3D objects with a small amount of instructions. Addon features include the ability to live code rules files, easy extensibility of the XML parser with custom actions and the ability to create rules programmatically. It’s inspired by Structure Synth and Philip Rideout’s Mesh Generation with Python.
The addon works by traversing a rules file (or the programatic equivalent of this) to create a tree data structure where each branch has a geometric transform. At each step, for each branch, a rule is chosen and executed. Each rule contains a set of actions that can create geometry and update the transform. Each action can also contain the name of a rule set to pick a rule from next.
The above mesh was generated with the following rules file…
1 2 3 4 5 6 7 8 9 | <rules maxDepth="6" primitive="triangles" meshColour="0" wireframeColour="255"> <ruleSet name="start"> <rule weight="100"> <ico radius="200" transforms="tx 400 ty 400 sa 0.5" next="start"/> <ico radius="200" transforms="tx 400 ty 400 ry 120 sa 0.5" next="start"/> <ico radius="200" transforms="tx 400 ty 400 ry 240 sa 0.5" next="start"/> </rule> </ruleSet> </rules> |
There is just one rule in this file and it executes three ico actions. Each ico action consists of…
- do the transform – move 400 units along the x axis, move 400 units along the y axis, scale all axes by 0.5
- draw an ico sphere
- execute the rule again (using the updated transform)
Usage
Clone ofxRules into your addons directory with the following commands:
1 2 | cd /path/to/openFrameworks/addons git clone https://github.com/neilmendoza/ofxRules.git |
Create a project using the openFrameworks project generator, you will need to select the both ofxRules and ofxXmlSettings as addons. There is a tutorial here about how to use the project generator if you are unfamiliar with it.
In your OF app somewhere declare an instance of ofxRules…
1 | ofxRules rules; |
In your setup() load the rules file you want to generate a mesh from (rules file syntax is detailed below)…
1 | rules.load("radical-thing.xml"); |
Step through the rules repeatedly, e.g. in the update(), to generate your mesh…
1 | rules.step() |
Draw the mesh…
1 | rules.draw() |
Live Coding
If you want to “live code” your rules file just call ofxRules::watchFile()…
1 | rules.watchFile("mmmm-live.xml"); |
…then every time the xml file is saved, the instance of ofxRules will be reset and the file traversed again.
Custom Actions
To create custom tags in your rules file you need to create a class that inherits from Action. At the minimum you will probably want to implement override/implement, the following functions:
1 | Branch::Ptr MyAction::step(Branch::Ptr branch, ofMesh& mesh); |
ofxRules::step() takes the previous branch and the mesh as parameters, you should update the mesh and branch transform and then return the branch.
1 | void MyAction::load(ofxXmlSettings& xml, const string& tagName, unsigned tagIdx); |
ofxRules::load() is where you parse your tag, you are passed a reference to an ofxXmlSettings with the current tag you are parsing pushed onto its stack.
Once you have implemented your action, you add it to your instance of ofxRules as follows…
1 | rules.registerAction<MyAction>("myAction"); |
…where “myAction” will be the name of the tag in the XML.
Programatic Definition of Rules and Actions
Rather than define everything in an xml file, it is also possible to create rule and actions programmatically, see example-programmatic for more details.
Tag Reference
Level 0 Tag – Root Tag
The <rules/> tag is the root tag of the document, its attributes contain data about the mesh.
1 2 3 | <rules maxDepth="500" startRule="start" primitive="triangles"> ... </rules> |
[table nl=”|”]
Attributes,Type,Default,Description
meshColour,colour,white,Specifies a global colour for the mesh. If this colour is not specified then colours can be specified for each primitive.
wireframeColour,colour,none,Specifies a colour for the wireframe. If this colour is not specified then the wireframe is not drawn.
maxDepth,int,none,Specifies the maximum depth to follow rules for.
primitive,”triangles”|”triangle_strip”|”triangle_fan”|”lines”|”line_strip”|”line_loop”|”points”,triangles,Primitive mode to use for mesh N.B. most primitives expect the mesh primitive mode to be triangles.
startRule,string,start,The name of the rule set to start with.
[/table]
Level 1 Tags – Rule Sets
<ruleSet/> tags are named set of rules. The rules file is traversed using these names.
1 2 3 4 5 6 7 8 | <rules> <ruleSet name="yin"> ... </ruleSet> <ruleSet name="yang"> ... </ruleSet> <rules> |
[table nl=”|”]
Attributes,Type,Default,Description
name,string,none,Name of the ruleSet.
[/table]
Level 2 Tags – Rules
<rule/> tags hold sets of contain sets of actions (see below). Once a ruleSet has been selected a rule is picked at random to execute. The weight attribute determines the likelihood of picking a rule.
1 2 3 4 5 6 7 8 | <ruleSet name="yin"> <rule weight="100"> ... </rule> <rule weight="50"> ... </rule> </ruleSet> |
[table nl=”|”]
Attributes,Type,Default,Description
weight,float,0.f,Probability of selecting the rule as given by weight/totalWeightOfRulesInRuleSet.
[/table]
Level 3 Tags – Actions
<transform/> tags update the transform for a branch. See below for transform syntax. All of the primitives can also contain a transform so only use the transform tag if you don’t want to create geometry in a step.
1 2 3 4 | <rule> <transform transforms="tx 200 ty 200 sa 0.5" next="yang"/> ... </rule> |
[table nl=”|”]
Attributes,Type,Default,Description
transforms,transform,identity,Transform to apply to the current transform for this branch (see below for transform syntax).
next,string,none,Name of next rule set to execute.
[/table]
<cube/> tags add a cube to the mesh.
1 2 3 4 | <rule> <cube transforms="tx 200 ty 200 sa 0.5" size="10" colour="255 0 0" next="yang"/> ... </rule> |
[table nl=”|”]
Attributes,Type,Default,Description
transforms,transform,identity,Transform to apply to the current transform for this branch (see below for transform syntax).
next,string,none,Name of next rule set to execute.
colour,colour,none,Colour of the cube (see below for colour syntax).
size,float,0.1f,Size of cube faces.
[/table]
<ico/> tags add an icosphere to the mesh.
1 2 3 4 | <rule> <ico transforms="tx 200 ty 200 sa 0.5" radius="10" iterations="10" next="yang"/> ... </rule> |
[table nl=”|”]
Attributes,Type,Default,Description
transforms,transform,identity,Transform to apply to the current transform for this branch (see below for transform syntax).
next,string,none,Name of next rule set to execute.
colour,colour,none,Colour of primitive (see below for colour syntax).
radius,float,0.1f,Radius of primitive.
iterations,int,2,Icosphere iterations.
[/table]
<cone/> tags add a cone to the mesh.
1 2 3 4 | <rule> <cone transforms="tx 200 ty 200 sa 0.5" next="yang"/> ... </rule> |
[table nl=”|”]
Attributes,Type,Default,Description
transforms,transform,identity,Transform to apply to the current transform for this branch (see below for transform syntax).
next,string,none,Name of next rule set to execute.
colour,colour,none,Colour of primitive (see below for colour syntax).
radius,float,1.f,Radius of primitive.
height,float,1.f,Height of primitive.
resolution,int,12,Resolution of primitive.
[/table]
<tube/> tags add a tube section to the mesh. The tube goes from the translation that corresponds to the transform before the rule is executed to the new translation once the transforms in the rule have been applied.
1 2 3 4 | <rule> <transform transforms="tx 200 ty 200 sa 0.5" next="yang"/> ... </rule> |
[table nl=”|”]
Attributes,Type,Default,Description
transforms,transform,identity,Transform to apply to the current transform for this branch (see below for transform syntax).
next,string,none,Name of next rule set to execute.
colour,colour,none,Colour of primitive (see below for transform syntax).
radius,float,5.f,Radius of primitive.
resolution,int,20,Resolution of primitive.
[/table]
<plane/> tags add a plane to the mesh.
1 2 3 4 | <rule> <plane transforms="tx 200 ty 200 sa 0.5" width="10" height="10" next="yang"/> ... </rule> |
[table nl=”|”]
Attributes,Type,Default,Description
transforms,transform,identity,Transform to apply to the current transform for this branch (see below for transform syntax).
next,string,none,Name of next rule set to execute.
colour,colour,none,Colour of primitive (see below for colour syntax).
width,float,1.f,Width of primitive.
depth,float,1.f,Depth of primitive.
[/table]
<line/> tags create two vertices, one before the transforms have been applied and one after. To use this you probably want to set the primitive attribute in the root tag accordingly.
1 2 3 4 | <rule> <transform transforms="tx 200 ty 200 sa 0.5" next="yang"/> ... </rule> |
[table nl=”|”]
Attributes,Type,Default,Description
transforms,transform,identity,Transform to apply to the current transform for this branch (see below for transform syntax).
next,string,none,Name of next rule set to execute.
[/table]
<point/> tags create one vertex before the transforms are applied. To use this you probably want to set the primitive attribute in the root tag accordingly.
1 2 3 4 | <rule> <transform transforms="tx 200 ty 200 sa 0.5" next="yang"/> ... </rule> |
[table nl=”|”]
Attributes,Type,Default,Description
transforms,transform,identity,Transform to apply to the current transform for this branch (see below for transform syntax).
next,string,none,Name of next rule set to execute.
[/table]
Attribute Syntax
Transforms
Transforms consist of strings representing translation, scaling and rotation that is very similar to the notation Philip Rideout used:
- tx n, ty n and tz n mean translate n units along the x, y or z axis respectively
- sx n, ty n and tz n mean scale the along the x, y or z axis by a factor of n
- sa n means scale all axes by a factor of n
- rx n, ry n and rz n means rotate around the x, y or z axis respectively by n degrees
Colours
Colours are specified in a similar way to openFrameworks:
- Three RGB bytes specified as numbers from 0 to 255 without a decimal point: colour=”255 0 0″
- One brightness byte specified as numbers from 0 to 255 without a decimal point: colour=”127″
- Three RGB float specified as numbers from 0.0 to 1.0 with a decimal point: colour=”1.0 0.0 0.0″
- One brightness float specified as numbers from 0.0 to 1.0 with a decimal point: colour=”0.5″
Recent Comments